Android與JS的交互彙總

1、首先看一下Android中webview的屬性設置

        //垂直不顯示
        this.setVerticalScrollBarEnabled(false);
        //設置編碼
        this.getSettings().setDefaultTextEncodingName("utf-8");
        //與JS交互必不可少的屬性
        this.getSettings().setJavaScriptEnabled(true);
        this.getSettings().setDomStorageEnabled(true);
        //支持JS打開新窗口
        this.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
        mStoreDetailJSObject = new StoreDetailJSObject(context);
        //綁定JS操作對象
        this.addJavascriptInterface(mStoreDetailJSObject, StoreDetailJSObject.JSOBJ_NAME);
        this.getSettings().setSupportZoom(true);
        //清理緩存
        clearCache(true);
        clearHistory();
        this.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
        this.getSettings().setPluginState(WebSettings.PluginState.ON);
        //擴大比例的縮放
        this.getSettings().setUseWideViewPort(true);
        //自適應屏幕
        this.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
        this.getSettings().setLoadWithOverviewMode(true);
        this.setOverScrollMode(OVER_SCROLL_NEVER);
        this.setFadingEdgeLength(0);

2、JS調用原生代碼

上面用到了addJavascriptInterface方法綁定與JS交互的對象,下面是StoreDetailJSObject類

public class StoreDetailJSObject {
	private JSWebView webView;
	private Context context;
	public static final String JSOBJ_NAME = "JSCallDetail";

	public StoreDetailJSObject(Context context){
		this.context = context;
	}
	public StoreDetailJSObject(Context context, JSWebView webView){
		this.context = context;
		this.webView = webView;
	}
	
	/**
	 * 獲取APP token
	 * @return
     */
	@JavascriptInterface
	public String getAppToken(){
		if (!CenterObserver.getInstance().isLogin()){
			context.startActivity(new Intent(context, LoginTrinityActivity.class));
		}
		return MyApplication.App.getToken();
	}
	
	/**
	 * 跳轉原生界面
	 */
	@JavascriptInterface
	public void appChannl(int id){
		if (PhoneUtils.isFastDoubleClick()){
			//連續點擊
			return;
		}
		Intent it = new Intent(context,MainActivity.class);
		context.startActivity(it);
	}
	/**
	 * 調用電話撥號
	 */
//	@JavascriptInterface
//	public void callTelServer(final String tel){
//		AlertDialog.Builder builder = new AlertDialog.Builder(context);
//		builder.setTitle(context.getResources().getString(R.string.tip_title));
//		builder.setMessage(tel);
//		builder.setNegativeButton(context.getResources().getString(R.string.cancel_dialog), null);
//		builder.setPositiveButton(context.getResources().getString(R.string.text_call_tel),
//				new DialogInterface.OnClickListener() {
//
//					@Override
//					public void onClick(DialogInterface arg0, int arg1) {
//						Intent intent = new Intent(Intent.ACTION_CALL,
//								Uri.parse("tel:" + tel));
//						context.startActivity(intent);
//					}
//				});
//		builder.show();
//	}
}

上面的@JavascriptInterface標註是JS調用原生必不可少的

那麼在JS中怎麼調用這些方法呢,上面的類中關聯了綁定對象名稱這裏叫JSCallDetail

so:

在JS中調用:JSCallDetail.getAppToken();即可

帶參:JSCallDetail.appChannl(int id);傳遞參數給Android端

3、原生調用JS代碼

a、通過loadUrl方法調用JS中的方法

 webView.loadUrl("javascript:show('"+info+"')");

b、根據ID獲取指定標籤的屬性

private void callJsCode() {
        String js =  "document.getElementById('can_share_url').value";
        
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
            mWebView.evaluateJavascript(js, new ValueCallback<String>() {
                @Override
                public void onReceiveValue(String value) {
                    LogUtil.e("can_share_url = "+value);
                }
            });
        }else{
            String value = mWebView.callJsMethodOld(js);
        }
 }

代碼中根據id爲can_share_url獲取對應標籤的value屬性的值在onReceiveValue方法中返回 不過使用evaluateJavascript方法調用JS代碼只能在SDK版本爲Build.VERSION_CODES.KITKAT(19,4.4)或者以上才行
那麼在4.4以下就要使用反射來實現了:

/**
     * 4.4之前通過java反射機制 調用JS
     * @param script
     * @return
     */
    public String callJsMethodOld(String script){
        try {
            //由webview取到webviewcore
            Field field_webviewcore = WebView.class.getDeclaredField("mWebViewCore");
            field_webviewcore.setAccessible(true);
            Object obj_webviewcore = field_webviewcore.get(this);
            //由webviewcore取到BrowserFrame
            Field field_BrowserFrame = obj_webviewcore.getClass().getDeclaredField("mBrowserFrame");
            field_BrowserFrame.setAccessible(true);
            Object obj_frame = field_BrowserFrame.get(obj_webviewcore);
            //獲取BrowserFrame對象的stringByEvaluatingJavaScriptFromString方法
            Method method_stringByEvaluatingJavaScriptFromString = obj_frame.getClass().getMethod("stringByEvaluatingJavaScriptFromString", String.class);
            //執行stringByEvaluatingJavaScriptFromString方法
            Object obj_value = method_stringByEvaluatingJavaScriptFromString.invoke(obj_frame, script);
            //返回執行結果
            return String.valueOf(obj_value);
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

同樣的如果是調用JS方法:

String js =  "show("+info+")";
        
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
            mWebView.evaluateJavascript(js, new ValueCallback<String>() {
                @Override
                public void onReceiveValue(String value) {
                    LogUtil.e("value= "+value);
                }
            });
        }else{
            String value = mWebView.callJsMethodOld(js);
        }
直接傳入方法就行,這些調用都限制在APP內部操作
3、外部瀏覽器調轉到App
a、使用原始方法
首先在AndroidManifest.xml的Activity下追加以下內容。

<intent-filter>  
    <action android:name="android.intent.action.VIEW"/>  
    <category android:name="android.intent.category.DEFAULT" />  
    <category android:name="android.intent.category.BROWSABLE" />  
    <data android:scheme="myapp" android:host="test.app" android:pathPrefix="/openwith"/>  
</intent-filter>
那麼在Html中
<a href="myapp://test.app/openwith?id=1">啓動應用程序</a>  

b、使用第三方jar包ActivityRouter (包含內部原生跳轉)
基於apt技術,通過註解方式來實現URL打開Activity功能,並支持在WebView和外部瀏覽器使用,支持多級Activity跳轉,支持Bundle、Uri參數注入並轉換參數類型。


特點


支持註解方式、手動方式註冊Activity。
支持注入Bundle、Uri的參數並轉換格式。
支持多級跳轉。
支持外部瀏覽器打開。
支持HTTP協議。
支持目標Activity的URL構造器訪問。
支持多個Module。


接入:https://github.com/joyrun/ActivityRouter


JS中有一個小技巧判斷調用內部JS打開原生還是調用外部連接打開APP
通過try catch來執行內部調用代碼 如:JSCallDetail.getAppToken();
若調用失敗會執行catch塊,所以在catch中執行外部瀏覽器打開APP的連接

try{  JSCallDetail.getAppToken();
}catch{window.location.href="myapp://test.app/openwith?id="+id}  如果沒有APP調轉到下載連接...


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章