I have created an Android app using WebView. This app shows the content of a website. There are many internal links and external links (with a 301 redirect). Internal links are correct, but when I tap on external links, I see a fullscreen desktop layout instead of the responsive version of the page and it looks very bad.
How do I edit the following code in order to always get the responsive layout to fit the screen?
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(final WebView view, String url) {
// hide loading image
Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
progressBar.setVisibility(View.GONE);
}
}, 1000);
}
#Override
public void onReceivedError(WebView view, int errorCode,String description, String failingUrl) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage(description).setPositiveButton(getText(R.string.ok), null).setTitle("onReceivedError");
builder.show();
}
});
// load url (if connection available
if (isInternetConnected(this)) {
String URL = "http://www.example.com/";
webView.loadUrl(URL);
}else{
// showAlertDialog(this, "No Internet Connection",
// "You don't have internet connection.", false);
new AlertDialog.Builder(this)
.setTitle("No Internet Connection")
.setMessage("You don't have internet connection.")
.setCancelable(false)
.setPositiveButton("Retry", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// whatever...
finish(); //Close current activity
startActivity(getIntent()); //Restart it
}
}).create().show();
}
Actually you are testing on a tablet and amazon website looks similar to desktop version from a tablet, while it becomes responsive when browsed from a phone.
Please try from a standard phone and you'll see that its mobile version of the site :)
Please let me know in case your problem isn't solved.
Thanks
Sanskar
Related
how can i force user to update my app by going to Google play store? if there's a new update a dialog will show which will have 2 buttons either update app or exit app.
Wont allow app to run unless latest version.
I am using eclipse and i cant migrate to android studio because of some project issues .
please help
Use Dialogs when your main Activity starts. Just redirect the user to the URL of your app on the PlayStore if he accepts, and exit the app (here are examples on how doing it).
Took from Anrdoid documentation :
public class YourDialogFragment extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(R.string.please_update)
.setPositiveButton(R.string.Ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// launch a browser with your PlayStore APP URL
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Exit the app
android.os.Process.killProcess(android.os.Process.myPid());
}
});
// Create the AlertDialog object and return it
return builder.create();
}
}
Now, when you create an instance of this class and call show() on that object, the dialog appears as shown in figure 1.
Just create an instance of it and use the show() method in your onCreateDialog from your MainActivity.
Note that Dialogs uses Fragments, which requieres API level 11. (You should be able to check the API level you're building to in your build.gradle file)
Use dialogs as mentioned by Noafix. Call an alert dialog when your version mismatches.
Also set dialog cancelable to false so that user cant remove dialog by pressing back!
private void showDialog()
{
final android.app.AlertDialog.Builder alertDialogBuilder = new android.app.AlertDialog.Builder(this);
alertDialogBuilder.setTitle("Update");
alertDialogBuilder.setMessage("Please update to continue?");
alertDialogBuilder.setIcon(R.drawable.warning);
alertDialogBuilder.setCancelable(false)
alertDialogBuilder.setPositiveButton("Confirm",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + appPackageName)));
}
});
// Add a negative button and it's action. In our case, just hide the dialog box
alertDialogBuilder.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
finishAffinity();
}
});
// Now, create the Dialog and show it.
final android.app.AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
}
You could get your version name as:
versionName = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0).versionName;
Now get your current version from your server using any rest client http calls and check with your version:
if(!versionName.equals(version)){showDialog();}
Note: For this you should implement a version file in server in which you must add new version in that file so that using http calls your app can get the new version name and check with app version!
Implement a way for the app to check if it is the latest version or not.
You can do this by hosting an update file that contains information on what the latest version is. This file is commonly in json format but can also be in any format you prefer. The app would have to query this update file and if the current version of the app is less than the version indicated in the update file, then it would show the update prompt.
If the app determines that an update is needed, open a dialog prompt then open the app's play store page
To launch a dialog prompt refer to the official Dialogs guide. Given that the question is not "how to launch a dialog" I will focus on discussing how to update the app.
To open google play store to a particular app page you must launch an intent with the View action and Market scheme uri like so
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + appPackageName)));
Be wary that if the device does not have google play store installed, then this will throw an exception. It is also possible for other apps to receive this type of intent and in the case where multiple apps can receive the intent, an app picker dialog will appear.
Challenges:
If the app must check for updates and can only run if it is the latest version, then the app cannot run if the device is not connected to the internet.
The app will have a hard dependency on google play store and cannot run if an update is needed and there is no play store on the device
If the update file is unavailable for any reason then the app will not run as well
You absolutely need the users to update to continue using the app, you could provide a simple versioning API. The API would look like this:
versionCheck API:
->Request parameters:
int appVersion
-> Response
boolean forceUpgrade
boolean recommendUpgrade
When your app starts, you could call this API that pass in the current app version, and check the response of the versioning API call.
If forceUpgrade is true, show a popup dialog with options to either let user quit the app, or go to Google Play Store to upgrade the app.
Else if recommendUpgrade is true, show the pop-up dialog with options to update or to continue using the app.
Even with this forced upgrade ability in place, you should continue to support older versions, unless absolutely needed.
try this: First you need to make a request call to the playstore link, fetch current version from there and then compare it with your current version.
String currentVersion, latestVersion;
Dialog dialog;
private void getCurrentVersion(){
PackageManager pm = this.getPackageManager();
PackageInfo pInfo = null;
try {
pInfo = pm.getPackageInfo(this.getPackageName(),0);
} catch (PackageManager.NameNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
currentVersion = pInfo.versionName;
new GetLatestVersion().execute();
}
private class GetLatestVersion extends AsyncTask
{
private ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected JSONObject doInBackground(String... params) {
try {
Document doc = Jsoup.connect(urlOfAppFromPlayStore).get();
latestVersion = doc.getElementsByAttributeValue
("itemprop","softwareVersion").first().text();
}catch (Exception e){
e.printStackTrace();
}
return new JSONObject();
}
#Override
protected void onPostExecute(JSONObject jsonObject) {
if(latestVersion!=null) {
if (!currentVersion.equalsIgnoreCase(latestVersion)){
if(!isFinishing()){
showUpdateDialog();
}
}
}
else
background.start();
super.onPostExecute(jsonObject);
}
}
private void showUpdateDialog(){
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("A New Update is Available");
builder.setPositiveButton("Update", new
DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse
("market://details?id=yourAppPackageName")));
dialog.dismiss();
}
});
builder.setNegativeButton("Cancel", new
DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
background.start();
}
});
builder.setCancelable(false);
dialog = builder.show();
}
I'm trying to add, in my android app, the legal notices for Google Maps v2 API, that can be obtained calling: GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo()
So, my code is the following:
String LicenseInfo = GooglePlayServicesUtil
.getOpenSourceSoftwareLicenseInfo(getApplicationContext());
AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(MyActivity.this);
LicenseDialog.setTitle("Lagal Notices");
LicenseDialog.setMessage(LicenseInfo);
LicenseDialog.show();
But when I execute this code, the system required about 10 seconds before the dialog is shown (considering that my device is a OnePlus One, it seems pretty strange) .
If I try to replace the LicenseInfo with a simple (shorter) string, the Dialog is open pretty fast. So I think that the problem is the length of the legal notices information retrieved from the Google play utils.
How can I solve this problem?
I had the same problem, but I found this on GitHub and based my solution on it. This does help but when the alert dialog shows, there is still a small hang on the UI thread but only for a few seconds.
https://github.com/wf9a5m75/phonegap-googlemaps-plugin/blob/master/src/android/plugin/google/maps/AsyncLicenseInfo.java
private class AsyncLoadLicenseInfo extends AsyncTask<Void,Void,AlertDialog.Builder>
{
#Override
protected void onPreExecute()
{
progressDialog = new ProgressDialog(context);
progressDialog.setIndeterminate(true);
progressDialog.setMessage(context.getResources().getString(R.string.LegalNoticesLoading));
progressDialog.setCancelable(false);
progressDialog.show();
}
#Override
protected AlertDialog.Builder doInBackground(Void... params)
{
String googleAttribution = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(context);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder
.setTitle(context.getResources().getString(R.string.AboutLegalNotices))
.setCancelable(false)
.setMessage(googleAttribution)
.setPositiveButton(context.getResources().getString(R.string.Close),null);
return builder;
}
#Override
protected void onPostExecute(AlertDialog.Builder builder)
{
AlertDialog attributionDialog = builder.create();
attributionDialog.setOnShowListener(new DialogInterface.OnShowListener()
{
#Override
public void onShow(DialogInterface dialog)
{
progressDialog.dismiss();
progressDialog = null;
}
});
attributionDialog.show();
}
}
As tasomaniac suggested, using WebView instead of TextView works without problems - there is just a small delay.
Here is the complete code to show the dialog:
private void legalDialog(){
String licenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(this);
licenseInfo = licenseInfo.replace("\n", "<br/>");
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.legal_notice);
WebView webView = new WebView(this);
webView.loadData("<html><body>"+licenseInfo+"</body></html>", "text/html", "utf-8");
WebSettings webSettings = webView.getSettings();
webSettings.setDefaultFontSize(12);
builder.setView(webView);
builder.setPositiveButton(R.string.dialog_close, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
final AlertDialog createDialog = builder.create();
createDialog.show();
}
Make sure to check if GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(this) doesn't return null, before calling legalDialog().
On a Motorola G5 running Android 6 the licence string returned by GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo() (or more recently GoogleApiAvailability.getInstance().getOpenSourceSoftwareLicenseInfo(getActivity())) is over 600,000 characters long. The delay occurs when loading the string into the TextView, which must be done on the UI thread.
LongStringLoader may be a solution to this. Full disclosure - I worked on the development team.
Another solution would be to use a WebView instead of a TextView.
You can have a really small Html template and you can fill its body with license text returned by
String result = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(this);
I was not able to show a progress dialog because the UI freezes. Plus the time consuming part was when dialog.show() took place and that could not be done on a background thread. Instead, I changed the text of the legal notices link to "Please wait" and then showed up the dialog with the legal notice. When the dialog dismissed I changed the text back to "Legal Notices" (Ofcourse the new dialog took up the whole screen where my background text was covered. If not then use dialog.setOnShowListener to change the text to/from Please Wait)
legalNoticeTV.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
legalNoticeTV.setText(getResources().getString(R.string.please_wait));
legalNoticeTV.setEnabled(false);
String result = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(this);
TextView tv = new TextView(this);
tv.setBackgroundColor(getResources().getColor(R.color.dialogbackgroundcolorgrey));
tv.setText(result);
tv.setPadding(8, 8, 8, 8);
ScrollView sc = new ScrollView(this);
sc.addView(tv);
legalNotice = new Dialog(this, R.style.DialogNoTitle);
legalNotice .requestWindowFeature(Window.FEATURE_NO_TITLE);
legalNotice.setContentView(sc);
legalNotice.show();
legalNotice.setOnDismissListener(new OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
legalNoticeTV.setText(getResources().getString(R.string.legal_notices));
legalNoticeTV.setEnabled(true);
}
});
}
});
While using WebView as in lenooh's answer, it is better to use TextUtils.htmlEncode(licenseInfo) instead of manually converting string to HTML string.
String licenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(this);
licenseInfo = TextUtils.htmlEncode(licenseInfo);
Is there a way I can put an if statement inside shouldOverrideUrlLoading() which checks for web/mobile access. Then display an error message instead of the nasty page not found page that mobile chrome displays.
Something similar to
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
if(isOnline() == false)
{
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this);
dlgAlert.setMessage("Mobile device currnetly has no internet access. Please try again.");
dlgAlert.setTitle("No Connection");
dlgAlert.setPositiveButton("OK", null);
dlgAlert.setCancelable(true);
dlgAlert.setIcon(R.drawable.ic_launcher);
dlgAlert.create().show();
}
return false;
}
Ok I found the solution for my problem. First of all I put the shouldOverrideUrlLoading() in new WevViewclient. Before I had it outside of that block.
Next I was getting an error message for
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this);
Next I changed the code to this, using Toast messages instead of AlertDialog Builder.
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
if (isOnline() == false)
{
Toast msg = Toast.makeText(MainActivity.this,"No mobile or web access, try again later.",Toast.LENGTH_LONG);
msg.show();
return true;
}
else
{
return false;
}
}
I'm developing an Android app which uses a webview to display a webpage. Most of my code is related to the webview. My main activity contains a webview which displays an specific web site.
I'm trying to prevent an error when my webview.db is corrupted. I know that is not a common situation but I would like to make sure that my app will not crash.
Attempting to access the webview database when it has been
corrupted will result in a crash.
I added the method setUncaughtExceptionHandler to handle the exception. I can catch the exeption but when I tried to restart my app the webview never finishes loading.
I tried the follow code to "restart" my app:
Intent i = new Intent(context, Error.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
My last try was unsuccessfully then I added some code which displays an error message, removes the webview databases and closes the app.
AlertDialog alertDialog = new AlertDialog.Builder(
DiscoverMobile.this).create();
alertDialog.setTitle("Error");
alertDialog.setMessage("Application files have been deleted or corrupted. The app will close to fix this issue. You can restart the app later");
alertDialog.setButton("OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
webview.getContext().deleteDatabase(
"webview.db");
webview.getContext().deleteDatabase(
"webviewCache.db");
WebViewDatabase webViewDB = WebViewDatabase
.getInstance(getBaseContext());
System.exit(0);
}
});
alertDialog.show();
Could this be a good solution?
Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.clearCache(true);
}
Maybe you tried this, but maybe also set the WebView Cache size to something small. I'm not sure if 0 will work, so maybe 1:
webview.getSettings().setAppCacheMaxSize(1);
Can anyone figure out why this causes a force close??
void failbox(){
// Create the alert box
AlertDialog.Builder alertbox = new AlertDialog.Builder(this);
// Set the message to display
alertbox.setMessage(R.string.fail);
alertbox.setPositiveButton("Get Busybox", new DialogInterface.OnClickListener() {
// do something when the button is clicked
public void onClick(DialogInterface arg0, int arg1) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse("market://details?id=stericson.busybox"));
}
});
// set a negative/no button and create a listener
alertbox.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
// do something when the button is clicked
public void onClick(DialogInterface arg0, int arg1) {
}
});
// show the alert box
alertbox.show();
}
Thanks in advance!
If you're getting the forced close in the emulator, that's just how it is, as best I can tell. You cannot access the market through the market app from an emulator.
Does your app still crash when run on a real Android device?
(Of course, some folks have figured out sneaky ways to get to the market from an emulator. See How to install Android Market App on the emulator?)