• 【转】 Android经验: proguard 阻碍 webview 正常工作


    转自:http://blog.csdn.net/span76/article/details/9065941

    WebView 常识

    使用 Alert  提供消息

    我在页面经常用 Alert 提供消息,  但 Android 需要你编写 MyWebChromeClient

    mWebView.setWebChromeClient(new MyWebChromeClient());  

    [html] view plaincopy
     
    1. final class MyWebChromeClient extends WebChromeClient {    
    2.         @Override    
    3.         public boolean onJsAlert(WebView view, String url, String message, JsResult result) {    
    4.             Log.d(LOG_TAG, message);    
    5.             result.confirm();    
    6.             return true;    
    7.         }    
    8.     }    


    当然类似还有 onJsConfirm , onJsPrompt 等, ref: http://developer.android.com/reference/android/webkit/WebChromeClient.html

    Android 与 JavaScript  的交互

    WebSettings webSettings = mWebView.getSettings(); 
            webSettings.setJavaScriptEnabled(true);  
            mWebView.addJavascriptInterface(new DemoJavaScriptInterface(), "demo");  

    [html] view plaincopy
     
    1. final class DemoJavaScriptInterface {    
    2.         public void clickOnAndroid() {    
    3.             mHandler.post(new Runnable() {    
    4.                 public void run() {    
    5.                     mWebView.loadUrl("javascript:wave()");    
    6.                 }    
    7.             });    
    8.     
    9.         }    
    10.     }   



    [html] view plaincopy
     
    1. <html>    
    2.     <script language="javascript">    
    3.         /* This function is invoked by the activity */    
    4.         function wave() {    
    5.             alert("1");    
    6.             document.getElementById("droid").src="android_waving.png";    
    7.             alert("2");    
    8.         }    
    9.     </script>    
    10.     <body>    
    11.         <!-- Calls into the javascript interface for the activity -->    
    12.         <a onClick="window.demo.clickOnAndroid()"><div style="80px;    
    13.             margin:0px auto;    
    14.             padding:10px;    
    15.             text-align:center;    
    16.             border:2px solid #202020;" >    
    17.                 <img id="droid" src="android_normal.png"/><br>    
    18.                 Click me!    
    19.         </div></a>    
    20.     </body>    
    21. </html>    


    程序详细内容 ref: http://bolutes.iteye.com/blog/1320344

    实战

    最近跑 0xbench 中 Android WebView 测试 sunspider 测试, 发现 sunspider 跑一阵就停留在白色屏幕,不知为何?

    打开 0xbench/src/org/zeroxlab/benchmark/TesterJavascript.java 看了看, 这个testcase比较简单

    [html] view plaincopy
     
    1. public class TesterJavascript extends Tester {  
    2.   
    3.     protected WebView mWebView;  
    4.     protected WebSettings mSettings;  
    5.   
    6.     private double mTotalTime = 0.0;  
    7.     private String mResult = "";  
    8.     private String mFormattedResult = "";  
    9.   
    10.     @Override  
    11.     public void onCreate(Bundle savedInstanceState) {  
    12.         super.onCreate(savedInstanceState);  
    13.         setContentView(R.layout.javascript);  
    14.         mWebView = (WebView) findViewById(R.id.web);  
    15.   
    16.         mSettings = mWebView.getSettings();  
    17.         mSettings.setJavaScriptEnabled(true);  
    18.         mWebView.addJavascriptInterface(new MsgCallback(), "ANDROID_OBJ");  
    19.   
    20.         startTester();  
    21.     }  
    22.   
    23.     @Override  
    24.     public void onResume() {  
    25.         super.onResume();  
    26.     }  
    27.   
    28.     @Override  
    29.     protected String getTag() {  
    30.         return "JavaScript";  
    31.     }  
    32.   
    33.     @Override  
    34.     protected int sleepBeforeStart() {  
    35.         return 1000;  
    36.     }  
    37.   
    38.     @Override  
    39.     protected int sleepBetweenRound() {  
    40.         return 1000;  
    41.     }  
    42.   
    43.     @Override  
    44.     protected void oneRound() {  
    45.         mWebView.loadUrl("file:///android_asset/driver.html");  
    46.     }  
    47.   
    48.     @Override  
    49.     protected boolean saveResult(Intent intent) {  
    50.         intent.putExtra(CaseJavascript.SUNSPIDER_RESULT, mResult);  
    51.         intent.putExtra(CaseJavascript.SUNSPIDER_FORMATTED_RESULT, mFormattedResult);  
    52.         intent.putExtra(CaseJavascript.SUNSPIDER_TOTAL, mTotalTime);  
    53.         return true;  
    54.     }  
    55.   
    56.     class MsgCallback {  
    57.         public void finish(String result, String formatted_result) {  
    58.             mResult = result;  
    59.             mFormattedResult = formatted_result;  
    60.             decreaseCounter();  
    61.         }  
    62.     }  
    63. }  


    就是打开 driver.html, 让其自动运行其中的 JS, 而后通过 JS callback MsgCallback.finish 把测试结果数据返回 

    在看看 0xbench/assets/driver.html 的代码段, 其中 

    [html] view plaincopy
     
    1. function finish()  
    2. {  
    3.     initialize();  
    4.     computeItemTotals();  
    5.     computeTotals();  
    6.     computeMeans();  
    7.     computeStdDevs();  
    8.     computeStdErrors();  
    9.   
    10.   
    11.     var formattedOutput = getOutputForUpload();  
    12.     var finalOutput = getOutput();  
    13.     window.ANDROID_OBJ.finish(finalOutput, formattedOutput);  
    14.   
    15.   
    16. }  

    其中: window.ANDROID_OBJ.finish(finalOutput, formattedOutput); 正是回调, ANDROID_OBJ 是 inject 的 obj 就是 MsgCallback 的实例

    让 html 调试方便

    每次都改 assets中的 html, 再安装调试是痛苦的

    在 TesterJavascript.java 把 mWebView.loadUrl("file:///android_asset/driver.html"); 改为

    mWebView.loadUrl("file:///sdcard/sunspider/driver.html");

    再把 asset 中的中文件 copy 到 sdcard/sunspider/ 下面

    以后每次调试只需要改写下 html ,而后可直接重新运行

    定位问题:
    [html] view plaincopy
     
    1. window.alert("before calling finish")  
    2. window.ANDROID_OBJ.finish(finalOutput, formattedOutput)  
    3. window.alert("after calling finish")  

    发现只弹出第一个对话框, 看来回调不成功, 后来又看了 log, 发现与设想一致

    E/Web Console(  343): Uncaught TypeError: Object org.zeroxlab.zeroxbenchmark.TesterJavascript$MsgCallback@a5972b68 has no method 'finish' at file ...

    解决:
    根据关键字google 了一些, 发现问题很可能是 proguard 把程序优化了(正如下面这篇文章提到的) , 因为 eclipse 编译的 0xbench 能在系统上跑, 而出问题的 0xbench 不是在 eclipse 中编译出来的

    http://stackoverflow.com/questions/7424510/uncaught-typeerror-when-using-a-javascriptinterface

    于是又回到那个简单的webviewdemo 程序, 检查build 系统是否出问题

    运行以前那个小程序, 发现同样问题, 再用 jd-gui 查看build系统 progruad刚处理过 proguard.classes.jar 果然方法被过滤掉了, 而proguard 处理之前的 jar 是有的

    在 Android.mk 中加入

    LOCAL_PROGUARD_FLAG_FILES := proguard.cfg

    在 Android.mk 同级目录中建立 proguard.cfg 内容是:

    [html] view plaincopy
     
    1. -keepclassmembers class com.pnp.webview.WebViewDemo.DemoJavaScriptInterface {  
    2.     <methods>;  
    3. }  


    但编译过程中, proguard 不认

    Proguard 编译命令是

    [html] view plaincopy
     
    1. external/proguard/bin/proguard.sh -injars out/target/common/obj/APPS/WebView_intermediates/classes.jar -outjars out/target/common/obj/APPS/WebView_intermediates/proguard.classes.jar -libraryjars out/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes.jar -include build/core/proguard.flags -forceprocessing -printmapping out/target/common/obj/APPS/WebView_intermediates/proguard_dictionary -include out/target/common/obj/APPS/WebView_intermediates/proguard_options   -include webview/proguard.cfg   

    报错是

    [html] view plaincopy
     
    1. Reading program jar [/home/payne/2jb/out/target/common/obj/APPS/WebView_intermediates/classes.jar]  
    2. Reading library jar [/home/payne/2jb/out/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes.jar]  
    3. Note: the configuration refers to the unknown class 'com.pnp.webview.WebViewDemo.DemoJavaScriptInterface'  
    4. Note: there were 1 references to unknown classes.  
    5.       You should check your configuration for typos.  

    ( 后来查明查明应该用)

    [html] view plaincopy
     
    1. -keepclassmembers class com.pnp.webview.WebViewDemo$DemoJavaScriptInterface {  
    2.     <methods>;  
    3. }  

    另外还可以用

    [html] view plaincopy
     
    1. -keep class com.pnp.webview.JavascriptCallback  
    2. -keep class * implements com.pnp.webview.JavascriptCallback  
    3. -keepclassmembers class * implements com.pnp.webview.JavascriptCallback {  
    4.     <methods>;  
    5. }  

    用jd-gui 打开, 却找不到相应的类

    终于想到了, jd-gui 也有可能出问题. 所以不管 jd-gui 了, 直接安装程序运行, 得到了想要的结果.

  • 相关阅读:
    二叉树遍历
    php环境搭建工具推荐
    laravel框架包资源分享
    memcached配置
    双引号转义问题
    PHP命名空间
    正则表达式
    2017,起航!
    关于大数据量下进行大数据展示的杂谈
    mysql空数据的处理
  • 原文地址:https://www.cnblogs.com/Mr-Nobody/p/3546641.html
Copyright © 2020-2023  润新知