Important Note:
A more effective solution is now available for Android 4.4+. It involves using a replacement for WebView
called CrossWalk. This new tool utilizes the latest Chromium-kit and has shown great results. For further details, visit: crosswalk-project.org
In addition, it seems that starting from Android 4.4, the workaround involving invalidate()
may no longer be necessary. Alternative solutions are recommended instead. Consider using invalidate()
only as a last resort.
I am sharing my own findings to assist others facing similar challenges.
I experimented with various methods to improve performance, including the commonly suggested -
webkit-transform: translate3d(0,0,0);
However, even this did not yield satisfactory results.
Allow me to share what did prove to be successful.
Firstly, ensure you are using the most recent API version. I am utilizing API 15. In your AndroidManifest.xml
, make sure to enable hardware acceleration. If your API version does not support this feature, proceed to the next step.
If hardware acceleration is supported in your API version, activate it by adjusting your manifest file accordingly:
<application
...
android:hardwareAccelerated="true">
Additionally, confirm that your manifest specifies the minimum supported API level matching the one you are using. Since I am on API 15, here is how my manifest is configured:
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="15" />
(Update: Modify these values in your build.gradle
)
Within your primary CSS file for content displayed in a WebView, incorporate the following style:
body div {
-webkit-transform: translate3d(0,0,0);
}
You can extend this styling to other element types present in your page, excluding images, ul
, li
, etc. Applying this style universally proved to be the most effective approach through trial and error. For larger DOM trees, you might need to be more specific. The exact specifications are still unclear.
Upon initializing your WebView
, configure certain settings:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.loadUrl("file:///android_asset/www/index.html");
appView.getSettings().setRenderPriority(RenderPriority.HIGH);
appView.getSettings()
.setPluginState(WebSettings.PluginState.ON_DEMAND);
}
Prior to concluding, an important discovery while examining the source code for the WebView
class revealed a comment regarding forceful redrawing. Within the class, there exists a static final boolean
attribute that, when set to true
, triggers constant redrawing of the view. As Java does not permit direct alteration of static final attributes, I resorted to extending the class as follows:
import org.apache.cordova.CordovaWebView;
import android.content.Context;
import android.graphics.Canvas;
public class MyWebView extends CordovaWebView {
public static final String TAG = "MyWebView";
public MyWebView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Caution! This will lead to continuous redraws of the WebView, potentially draining the device's battery during view display!
invalidate();
}
}
Please note that being a Cordova/PhoneGap user, I had to extend from CordovaWebView
. Notably, the onDraw
method calls invalidate
, prompting constant redrawing of the view. It is advisable to implement logic ensuring redraws occur only when necessary.
A final requirement, if employing Cordova, involves instructing PhoneGap to utilize your custom WebView
class instead of its default counterpart. In your MainActivity
class, include the following:
public void init(){
CordovaWebView webView = new MyWebView(MainActivity.this);
super.init(webView, new CordovaWebViewClient(this, webView), new CordovaChromeClient(this, webView));
}
That concludes the process! Test your application to observe enhanced performance. Prior to implementing these changes, pages may have appeared white initially, CSS alterations delayed until screen interaction, and animations exhibiting choppy behavior or inconsistency. While animation smoothness remains somewhat compromised, the improvement is significant compared to before.
If there are additional insights to contribute or better alternatives to suggest, feel free to leave a comment. Optimization suggestions are welcomed, acknowledging potential room for enhancement in the proposed approach.
If the aforementioned solution does not address your situation, kindly describe your specific scenario and any issues encountered with Android's WebView
.
Finally, this answer has been designated as a "community wiki", permitting adjustments from all users. Contributions are encouraged!
Thank you!
Update:
With the most recent version of PhoneGap, your init()
method should resemble this structure:
public void init(){
CordovaWebView webView = new MyWebView(MainActivity.this);
super.init(webView, new IceCreamCordovaWebViewClient(this, webView), new CordovaChromeClient(this, webView));
}