天天看點

androidh5混合開發_混合開發,h5調用android原生子產品 Action

h5原生混合開發已經有些年頭了,說實在的h5調用原生最好用的還是在h5發起新連結的時候攔截下來,然後原生做出反應。

思路是自定義一套原生h5互動協定,使用者在h5頁面點選的時候,h5發起一個跳轉(location=“”),用戶端攔截這個跳轉,如果符合協定的跳轉,就交給用戶端進行操作

否則傳回給浏覽器,進行正常的跳轉

定義:我們把h5發起讓原生處理的請求定義為action

代碼示例:

public class MyWebViewClient extends WebViewClient {

private MyWebView mWebView;

public MyWebViewClient(MyWebView webView) {

super();

mWebView = webView;

}

@Override

public boolean shouldOverrideUrlLoading(WebView view, String url) {

if (NativeInvokeFilter.filter(url, mWebView)) {

return true;

} else {

return super.shouldOverrideUrlLoading(view, url);

}

}

}

自定義webview,統一使用該webview來處理h5調用原生的需求

package com.example.base.basetemplate.widget.MyWebView;

import android.annotation.SuppressLint;

import android.content.Context;

import android.os.Build;

import android.util.AttributeSet;

import android.webkit.WebSettings;

import android.webkit.WebView;

public class MyWebView extends WebView {

public MyWebView(Context context) {

super(context);

init();

}

public MyWebView(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

@SuppressLint("SetJavaScriptEnabled")

private void init() {

setWebViewClient(new MyWebViewClient(this));

WebSettings settings = getSettings();

if (settings != null) {

settings.setJavaScriptEnabled(true);

settings.setDomStorageEnabled(true);

settings.setAllowContentAccess(true);

settings.setTextSize(WebSettings.TextSize.NORMAL);

settings.setAllowFileAccess(false);

settings.setSavePassword(false);

settings.setCacheMode(WebSettings.LOAD_NO_CACHE);

settings.setBlockNetworkImage(false);

// TODO: SDK修改成21後再設定

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);

}

// settings.setAppCacheEnabled(true);

// settings.setAppCacheMaxSize(1024 * 1024 * 8);

// String appCacheDir = getContext().getDir("cache", Context.MODE_PRIVATE).getPath();

// settings.setAppCachePath(appCacheDir);

}

setHorizontalScrollBarEnabled(false);

}

}

至于自定義webview的調用,就不再啰嗦了

NativeInvokeFilter

處理action的核心類

package com.example.base.basetemplate.nativeinvokefilter;

import android.text.TextUtils;

import com.example.base.basetemplate.nativeinvokefilter.handler.OneActionHandler;

import com.example.base.basetemplate.widget.MyWebView.MyWebView;

import java.io.UnsupportedEncodingException;

import java.net.URLDecoder;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.Map;

public class NativeInvokeFilter {

//請求頭部

public static final String SCHEMA = "myappschema://myappschema?";

//此handler和java系統的handler沒有任何關系,易于擴充性展現在新加的action必須實作這個接口,統一放在同一個目錄下

public interface NativeHandler {

void handle(NativeInvokeProtocol nip, MyWebView webView);

}

private static final Map TYPE_MAP = new HashMap();

public enum Type {

UNKNOWN("unknown", null),

ONEACTION("oneaction",new OneActionHandler());

private NativeHandler mHandler;

Type(String key, NativeHandler handler) {

TYPE_MAP.put(key, this);

mHandler = handler;

}

public static Type parse(String key) {

if (TextUtils.isEmpty(key)) {

return UNKNOWN;

}

Type type = TYPE_MAP.get(key);

return type == null ? UNKNOWN : type;

}

public static NativeHandler getHandler(String key) {

return parse(key).mHandler;

}

}

public static boolean filter(String url, MyWebView webView) {

if (canParse(url)) {

NativeInvokeProtocol nip = NativeInvokeProtocol.fromParamString(

url.substring(SCHEMA.length()));

if (nip != null)

return handleInvoke(nip, webView);

}

return false;

}

private static boolean canParse(String url) {

if (TextUtils.isEmpty(url)) {

return false;

}

return url.startsWith(SCHEMA);

}

private static boolean handleInvoke(NativeInvokeProtocol nip, MyWebView webView) {

// 優先使用newAction字段

String realAction = null == nip.newAction || 0 == nip.newAction.length() ? nip.action : nip.newAction;

if (TextUtils.isEmpty(realAction))

return false;

NativeHandler handler = Type.getHandler(realAction);

if (handler != null) {

handler.handle(nip, webView);

return true;

} else

return false;

}

public static class NativeInvokeProtocol {

private static final String ACTION = "action";

private static final String NEW_ACTION = "newAction";

private static final String INFO = "info";

private static final String LEFT_BRACE = "{";

private static final String RIGHT_BRACE = "}";

private static final String EQUAL = "=";

private static final String AND = "&";

private static final String SHARP = "#";

private String action;

private String newAction;

private String url;

public String info;

public String getUrl() {

return url;

}

public String getAction() {

return action;

}

public static NativeInvokeProtocol fromParamString(String paramStr) {

NativeInvokeProtocol nip = new NativeInvokeProtocol();

if (TextUtils.isEmpty(paramStr)) {

return nip;

}

try {

paramStr = URLDecoder.decode(paramStr, "UTF-8");

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

// 循環掃描字元串,找出最外層的&(不在{}之間)所在位置,分隔字元串

int len = paramStr.length();

ArrayList outterAnds = new ArrayList();

// {或者}标記,遇到{加1,遇到}減1,等于0即表示目前掃描位置不在{}之間

int braceIndicator = 0;

for (int i = 0; i < len - 1; i++) {

String ch = paramStr.substring(i, i + 1);

if (ch.equals(AND) && braceIndicator == 0) {

outterAnds.add(i);

}

if (ch.equals(LEFT_BRACE)) {

braceIndicator++;

}

if (ch.equals(RIGHT_BRACE)) {

braceIndicator--;

}

}

// 加上字元串首尾位置

outterAnds.add(0, -1);

outterAnds.add(paramStr.length());

HashMap paramMap = new HashMap();

for (int i = 0; i < outterAnds.size() - 1; i++) {

String paramItemStr = paramStr.substring(outterAnds.get(i) + 1, outterAnds.get(i + 1));

int keyIndex = paramItemStr.indexOf(EQUAL);

String key = paramItemStr.substring(0, keyIndex);

String value = paramItemStr.substring(keyIndex + 1);

paramMap.put(key, value);

}

nip.action = paramMap.get(ACTION);

if(null!=nip.action && nip.action.length()>0 && nip.action.contains(SHARP))

nip.action = nip.action.split(SHARP)[0];

nip.info = paramMap.get(INFO);

nip.newAction = paramMap.get(NEW_ACTION);

return nip;

}

}

}

一個非常簡潔的handler

public class OneActionHandler implements NativeHandler {

@Override

public void handle(NativeInvokeProtocol nip, MyWebView webView) {

Toast.makeText(MyEnvironment.activity(),nip.info,Toast.LENGTH_SHORT).show();

}

}

html上的簡單調用

h5調用原生

測試

測試的時候,html可以放在assets檔案夾下面,或者放在伺服器上