最近在開發一個模組的時候,有一個Activity嵌套了html5頁面,但是發現了一個問題,就是Debug包是可以正常調用Android本地方法的,而Release包則無法調用同一個本地方法。
代碼如下:
public class FlaggingActivity extends AppBaseActivity { @Initialize NavigateBar navigateBar; @Initialize WebView webView; String url = NetComment.getIns().getH5()+"/html/fedback/index.html?"; String strId; String strTel; String strType; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent=getIntent(); strId = intent.getStringExtra("id"); strTel = intent.getStringExtra("tel"); strType = intent.getStringExtra("type"); url = url +"id="+strId+"&type="+strType+"&tel="+strTel+"&device=2"; setContentView(R.layout.activity_flagging); findAllViewByRId(R.id.class); WebSettings webSetting = webView.getSettings(); //設定js可用 webSetting.setJavaScriptEnabled(true); // 添加js調用介面 webView.addJavascriptInterface(this,"android"); webView.getSettings().setJavaScriptEnabled(true); webView.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } }); webView.loadUrl(url); } @JavascriptInterface public void close(String token) { //關閉當前activity this.finish(); }}
從上面的代碼可以看出,我這裡就是在Activity裡嵌套了一個webview,webview的內容指向一個html頁面。然後在html頁面通過Js再去反向調用Android本地的close方法。
然而,在這裡出現了上文的問題:就是Debug包是可以正常調用Android本地方法的,而Release包則無法調用同一個本地方法。
經過排查,我發現了:在我的Android項目裡,Debug包是未混淆的,而Release包是經過混淆的,問題也的確就出現在混淆上。混淆的作用是:為了防止自己的勞動成果被別人竊取,混淆代碼能有效防止被反編譯。那麼同樣地,因為混淆功能的開啟,導致本地的close()方法,在經過混淆之後可能並不再是close()這個函數名稱了,那就導致我們的js無法找到這個方法,也就無法調用close()方法了。
相應的解決方式也就是讓close()方法不參與混淆,我這裡的範圍稍微大了一些,是直接把當前的類設定成為了不可混淆,如下(添加在proguard-rules.pro檔案中):
#html互動本地方法不能被混淆-keepclassmembernames class com.android.app.activity.house.FlaggingActivity {*;}
加上上面的代碼塊中後,我們的release包也可以找到close()方法了。
其實這個問題很好解決,在這裡記錄下來的原因就是一般情況下,Debug包是不混淆的,而Release包通常作為上線包是需要混淆的。但是我們在測試的時候通常使用的是Debug包,在Debug包測試無誤的時候通常對於Release包的測試就會掉以輕心。當我們使用js調用本地方法或者反射的時候,這是玩玩不可以的。所以也就要求我們在上線的時候最好對於Release包也進行一個相對完整的測試,以減少類似的失誤。