I'm trying to make a app with WebView, but the website is using https, but the content (ex. mp3 file) uses http, so Android Lollipop won't load it because it is "Mixed Content". I tried to use onReceivedSslError handler.proceed();, but it doesn't load anything. Is there a way to fix it? or could I just make all websites loaded use http, so It doesn't show any errors?
Since Pie (API 29), all non-HTTPS traffic in app is now disabled by default.
If you're targeting API level 26 or above, you must first enable it in the manifest file. Add
android:usesCleartextTraffic="true"
into <application> tag.
Since Lollipop (API 21), WebView blocks all mixed content by default.
To change this behaviour, when you are targeting API level 21 or above, use:
webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
In this mode, the WebView will attempt to be compatible with the
approach of a modern web browser with regard to mixed content. Some
insecure content may be allowed to be loaded by a secure origin and
other types of content will be blocked. The types of content are
allowed or blocked may change release to release and are not
explicitly defined.
In practice this should allow loading of images, videos, music etc. - all content that has low probability of being major security threat, when tampered/replaced by malicious third-party.
Alternatively use (strongly discouraged):
webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
In this mode, the WebView will allow a secure origin to load content
from any other origin, even if that origin is insecure. This is the
least secure mode of operation for the WebView, and where possible
apps should not set this mode.
If your min API is less than 21 and cannot call setMixedContentMode directly, you can use reflection:
try {
Method m = WebSettings.class.getMethod("setMixedContentMode", int.class);
if ( m == null ) {
Log.e("WebSettings", "Error getting setMixedContentMode method");
}
else {
m.invoke(webView.getSettings(), 2); // 2 = MIXED_CONTENT_COMPATIBILITY_MODE
Log.i("WebSettings", "Successfully set MIXED_CONTENT_COMPATIBILITY_MODE");
}
}
catch (Exception ex) {
Log.e("WebSettings", "Error calling setMixedContentMode: " + ex.getMessage(), ex);
}
In android pie in addition to setting the mixed content mode, you also need to set the android:usesCleartextTraffic attribute in the AndroidManifest.
In your AndroidManifest.xml do:
<application
....
android:usesCleartextTraffic="true"
...>
and when setting up the webview, do:
webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
to load it conditionally on API >= 21, you don't have to use reflection.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
}
I've recently migrated from Crosswalk to use the native WebView.
Had to fight with this issue for a few hours. The fix was to run clearCache() prior to setting the settings.
webView.clearCache(false); // <-- DO THIS FIRST
webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
Go to manifest.xml and add the following line.
android:usesCleartextTraffic="true"
And in Java file of webview add this code.
webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
If you are running into this problem, just make sure you have installed the Ionic's WebView Cordova Plugin (https://github.com/ionic-team/cordova-plugin-ionic-webview). The easiest way is to check your package.json.
Once installed:
Open your config.xml file
Check if you have an entry for <preference name="Scheme">
If you do, check that the value is "https".
If you don't have it, then add this line:
<preference name="Scheme" value="https" />
Add this line:
<preference name="MixedContentMode" value="0" />
This solved the problem for me.
Related
My webview has drawing functionality inside a canvas which was working fine. But after upgradation of Chrome it stopped drawing inside canvas. I have a work around, by setting hardware acceleration true it works perfectly, but issue is my app's memory consumption increased rapidly. Is there any solution of this problem?
I am using Cordova for cross platform.
Well, I don't know about Cordova, but I think this can also help you. I found that the key to solving the HTML5 canvas issue in Android webview is within AndroidManifest.xml. What did I have to do? I kept the strategy of using a hybrid (custom) webview, because as I develop in Xamarin Forms for both iOS and Android, I needed the same solution on both platforms. On Android I did:
// Java (or similar [laughs])
// Enable hardware acceleration using code (>= level 19)
if (Build.VERSION.SDK_INT >= 19) {
yourWebviewObj.setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else {
yourWebviewObj.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
yourSettingsObj.setRenderPriority(WebSettings.RenderPriority.HIGH);
yourSettingsObj.setCacheMode(WebSettings.LOAD_NO_CACHE);
// Xamarin for Android
// Enable hardware acceleration using code (>= level 19)
if (Build.VERSION.SdkInt >= 19)
{
yourWebviewObj.SetLayerType (LayerType.Hardware, null);
}
else
{
yourWebviewObj.SetLayerType (LayerType.Software, null);
}
yourWebviewObj.Settings.SetRenderPriority(WebSettings.RenderPriority.High);
yourWebviewObj.Settings.CacheMode = CacheModes.NoCache;
And finally, within AndroidManifest.xml find for android:handwareAccelerated="false" and you can change the value from false to true. This tip (additionally) works for both the Java universe and Xamarin.
Had another person with the same problem at Android WebView with layer_type_software not showing HTML5 canvas content where I also posted the same solution. Sorry if my help was not enough, but today I develop applications using Xamarin. Anyway I believe that following this path will help you.
I'm using Crosswalk (XwalkView) instead of the default Webview on Android but it seems that the defalt pull-to-refresh functionality doesn't work on Android 4.3. I've tested it on 5.0 and it's ok, but on 4.3 and 4.2.2 it doesn't work. I'm guessing it has to do with < 5.0 ?!
I've tried something like this to enable it, but it failed to work:
//Disable the edge effect and try to enable pull to refresh in case we're using xwalk webviews
if (BuildConfig.IS_XWALK) {
final String INIT_SWITCHES[] = {"Xwalk", "--enable-pull-to-refresh-effect", "--disable-overscroll-edge-effect"};
if (!CommandLine.isInitialized()) {
CommandLine.init(INIT_SWITCHES);
}
}
Any ideas ?
Actually, we already have a JIRA about this feature, please track it here: https://crosswalk-project.org/jira/browse/XWALK-6277.
It has some block issue before, but we will continue investigating how to implement it.
I have a button that I want to set the background of using a png file from internal storage. For android api 16 and up, this works fine:
filePath = getActivity().getFileStreamPath(colorCodes.get(i-1));
temp.setBackground(Drawable.createFromPath(filePath.toString()));
When running on an android tablet with 4.0.4, this part crashes the app with a nosuchmethod error (setBackground). After a little research, I see that setBackground is only available for api 16+. After looking around on SO and a few other places, it looks like I need to use setBackgroundDrawable (deprecated) or setBackgroundResource. I tried this:
filePath = getActivity().getFileStreamPath(colorCodes.get(i-1));
if (android.os.Build.VERSION.SDK_INT < 16) {
temp.setBackgroundDrawable(Drawable.createFromPath(filePath.toString()));
} else {
temp.setBackground(Drawable.createFromPath(filePath.toString()));
}
When logging it out, it shows that setBackgroundDrawable is running and not setBackground, but I get the same nosuchmethod error (setBackground).
The other option is setBackgroundResource, but it accepts an int and not a drawable. Can I convert from drawable to int for this purpose?
What can I do here to set the background of the button to a file in internal storage for APIs < 16?
Thanks.
***EDIT - ok, this is working. just missed a little part elsewhere in the code that had the same problem. However, is using a deprecated method really the only way?
Deprecation is a status applied to a computer software feature,
characteristic, or practice indicating it should be avoided, typically
because of it being superseded. The term is also sometimes used for a
feature, design, or practice that is permitted but no longer
recommended in other areas, such as hardware design or compliance to
building codes. (source link)
Now we can answer your question.
Before API level 16 there is a method named setBackgroundDrawable. After API Level 16 google decided to write a new method setBackground for same purpose and recommend us to use new method. (Reason of this may be found by googling.)
You can use setBackgroundDrawable method for all api levels. There aren't any constraint for this. But using new method setBackground is recommended after API Level 16.
But you can only use setBackground method for devices which is running on API Level 16 or higher. So if you only implement setBackground method in your code, you are going to get MethodNotFoundException for devices which run below API Level 16.
To sum up; it is a best practice(for me it is a must) to use new methods then deprecated ones with supportted api version check such as;
if (android.os.Build.VERSION.SDK_INT < 16) {
temp.setBackgroundDrawable(Drawable.createFromPath(filePath.toString()));
} else {
temp.setBackground(Drawable.createFromPath(filePath.toString()));
}
I am not quite sure whether it is the only way to achieve this but in my opinion it is the correct one. Because the annotation #Deprecated defines the method to be superseded (in most cases) it automatically implies you can (I would even say should) use it to address older versions which are the targeted versions of this method.
Is there any kind of conditional compiling for Android?
I had to make my project for Android 3 (API 11) just because ExifInterface has almost no useful attributes in Android 2.3 (API 10), despite the fact that it appeared in API 5 (!!??). I don't want to restrict my app to ICS users.
Thanks!
You can check dynamically the current API version of the device and do different stuff depending on that:
if(Build.VERSION.SDK_INT < 14) {
// Crappy stuff for old devices
}
else {
// Do awesome stuff on ICS
}
But be careful that if you need to instantiate classes that are not available for all APIs then you should do it in a runnable or in a separate wrapper class, e.g:
if(Build.VERSION.SDK_INT < 14) {
// Crappy stuff for old devices
}
else {
// Do awesome stuff on ICS
new Runnable() {
new AmazingClassAvailableOnICS();
(...)
}.run();
}
import android.annotation.TargetApi;
and then use annotations:
#TargetApi(11)
public void methodUsesAPI11()
{
...
Using this trick does a very simple thing: it allows compiling some code which contains API level 11 calls (classes, methods, etc) and still set android:minSdkVersion="8" in the manifest. Nothing more, nothing else.
The rest is up to you. You must check platform version before you call methodUsesAPI11() or you handle exceptions in order to prevent app crash and perform other action on older platforms.
Checking Build.VERSION.SDK_INT or using annotations should suffice, however, this link I'd bookmarked might be relevant to your case:
http://android-developers.blogspot.com/2010/07/how-to-have-your-cupcake-and-eat-it-too.html?m=1
You can use what they describe there to have classes that may not be compatible, but will never be loaded. It's not conditional compilation, but it may be what you need, however, it is a bit more complex.
In the past, I have changed a normal Webview property on Android. For example:
wv.getSettings().setAllowUniversalAccessFromFileURLs(true);
where wv is a variable of webview. Now, I have an phonegap/cordova app, and I want to change
the same line of code, I have been trying the the following way:
super.appView.getSettings().setAllowUniversalAccessFromFileURLs(true);
and also like:
super.appView.getSettings().setAllowUniversalAccessFromFileURLs(true);
I don't get any compiling errors, but when I add that line of code on the onCreate method, the app just closes. I have been trying to add the line on the onCreate method at different places, like, before and after the super.onCreate and before and after loading the html (super.loadUrl("file:///android_asset/www/index.html"), but the app always closes. Any of you know if it is possible to change that property on phonegap/cordova ?
That code is already in our web view so you don't need to set it. Probably the reason it is crashing is that you are not running on an ICS device. That method is only available in ICS or better.
If you really want to add it do:
if(android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
super.appView.getSettings().setAllowUniversalAccessFromFileURLs(true);
}