2014年12月7日 星期日

[android] proGuard 導致 webview AndroidJSInterface / WebAppInterface 失效問題

開啟 proGuard 混淆器 會導致 webview AndroidJSInterface 失效

第一次發現這個問題是

在使用eclipse debug的時候 AndroidJSInterface 的 function 可以正常執行



[mainActivity.java]
package com.example.proguardexample;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.webkit.WebSettings;
import android.webkit.WebView;

public class MainActivity extends Activity {
 private WebView myWebView;
 private String url;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  url = "file:///android_asset/webview.html";
  myWebView = (WebView) findViewById(R.id.webView1);

  WebSettings webSettings = myWebView.getSettings();
  // 啟用javascript
  webSettings.setJavaScriptEnabled(true);

  myWebView.loadUrl(url);

  // 用js呼叫 android function
  myWebView.addJavascriptInterface(new WebAppInterface(this), "Android");

  // 自建一個interface 來客制化 webview導向要作的動作
  myWebView.setWebViewClient(new MyWebViewClient() {
   @Override
   public void launchExternalBrowser(String url) {
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
    startActivity(intent);
   }
  });
 }
}
[WebAppInterface.java]
package com.example.proguardexample;

import android.content.Context;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.widget.Toast;

public class WebAppInterface {
 Context mContext;

 WebAppInterface(Context c) {
  mContext = c;
 }

 @JavascriptInterface
 public void showToast(String toast) {
  Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
 }
}

[webview.html]




[proguard-project.txt]
#拿掉 proguard-project.txt 中的註解 開啟proGuard 混淆機制
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt


不過 安裝 打包好後的 APK檔案 之下卻沒有執行

內容是一模一樣的程式碼

就想到 使用 dex2jar 去反解 原始碼看看

反編譯 [WebAppInterface.java] proguard 混淆後
package com.example.proguardexample;

import android.content.Context;

public class c
{
  Context a;

  c(Context paramContext)
  {
    this.a = paramContext;
  }
}

發現了兩個原因 造成 javascriptInterface失效

1.@JavascriptInterface 註解消失了

(android 4.2以上, targetSdkVersion 17 以上 必須此註解)

2.整個 showToast function 也消失了

js 呼叫 function 
showAndroidToast(toast) {
  Android.showToast(toast);
}
的時候 找不到 showToast function

解決方案

設定 proguard-project.txt 檔案 加入

[proguard-project.txt]
#留下WebAppInterface 及其下的 方法
 -keep class  com.example.proguardexample.WebAppInterface
 -keepclassmembers class  com.example.proguardexample.WebAppInterface {
    <methods>; 
 }

#留下 @JavascriptInterface 註解
-keepattributes JavascriptInterface

如果你的WebAppInterface 不是獨立出來的class
例如是在 mainActivity 的 subclass
可以使用錢字號 $ 的方式寫

[proguard-project.txt]
-keep class com.example.proguardexample.MainActivity$WebAppInterface 
 -keepclassmembers class com.example.proguardexample.MainActivity$WebAppInterface {
    <methods>; 
 }

設定完成後 javascriptInterface 的功能就恢復正常了!


沒有留言:

張貼留言