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;

/**

* Created by cgx on 2017-6-15.

*/

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;

/**

* Created by cgx on 2017-6-15.

*/

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();

/**

* 日后可以在Type里面添加新的action,首先要定义好action对应的字段(第一个参数)和对应的handler

*/

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;

}

/**

* 检测传递的url,如果以SCHEMA开头就可以执行action的操作

* @param url

* @return

*/

private static boolean canParse(String url) {

if (TextUtils.isEmpty(url)) {

return false;

}

return url.startsWith(SCHEMA);

}

/**

* 执行handler的方法,首先查找TYPE_MAP,通过action来查找到对应的handler,如果有找得到就执行handler的handle方法

* @param nip

* @param webView

* @return

*/

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;

}

/**

* 解析action链接头部的类,重点的变量是info,action返回的信息体,通常是一个json字符串

* 变量action,对应具体的业务

*/

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文件夹下面,或者放在服务器上

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值