WebView跨进程通信框架源码分析

本文详细介绍了WebView与Native的通信方式,包括创建JavascriptInterface接口、命令分发、Aidl初始化与实现,以及跨模块接口服务调用的流程。通过建立命令模式,将JavaScript与Native之间的交互转化为命令执行,实现通信框架。此外,还讨论了如何通过AIDL实现在不同进程间进行命令分发,以及服务的发布和获取,以实现模块间的解耦调用。
摘要由CSDN通过智能技术生成

我们都知道webView是加载解析网页代码用的,但是如果webView加载的网页数据过大的话就会消耗本进程的内存空间,从而影响app的性能;因为,系统给每个app的进程分配的空间是有限的,过多的使用空间会造成进程空间资源不足;因此,遇到这种情况我们最好给webView开一个独立进程,这样的话app主进程就节省了加载webView资源的空间

webView与native通信

我们知道js要想调用native代码的话,需要在webView里面添加addJavascriptInterface;js在调用native代码的时候无非就是根据不同的行为传递不同的参数的问题,那这样的话,我们不妨用类似命令模式的方式,来定义一个命令接口,然后当js调用JavascriptInterface的方法的时候,通过传递不同的action 与params到native代码,然后通过命令分发来执行不同的命令,这样的话就实现了一个简单的通信框架,如图所示:
在这里插入图片描述

具体步骤如下:

创建JavascriptInterface接口

首先我们在webView初始化的时候创建出与js通信的接口:

public final class WebviewJavascriptInterface {
   

    private final Context mContext;
    private final Handler mHandler = new Handler();
    private JavascriptCommand javascriptCommand;

    public WebviewJavascriptInterface(Context context) {
   
        mContext = context;
    }

    @JavascriptInterface
    public void post(final String cmd, final String param) {
   
        mHandler.post(new Runnable() {
   
            @Override
            public void run() {
   
                try {
   
                    if (javascriptCommand != null) {
   
                        javascriptCommand.exec(mContext, cmd, param);
                    }
                } catch (Exception e) {
   
                    e.printStackTrace();
                }
            }
        });
    }

    public void setJavascriptCommand(JavascriptCommand javascriptCommand) {
   
        this.javascriptCommand = javascriptCommand;
    }

    public interface JavascriptCommand {
   
        void exec(Context context, String cmd, String params);
    }
}

然后将这个接口设置到webView里面就行了

命令分发

接着定义一个webViewCallBack接口,这个接口是将javascriptCommand.exec()回调给webViewCallBack,相当于一个代理吧,webViewCallBack可以让fragment实现然后去做分发处理:

public interface WebViewCallBack {
   

    int getCommandLevel();

    void pageStarted(String url);

    void pageFinished(String url);

    boolean overrideUrlLoading(WebView view, String url);

    void onError();

    void exec(Context context, int commandLevel, String cmd, String params, WebView webView);
}

可以让fragment或者activity实现这个接口,如下所示:

    @Override
    public void exec(Context context, int commandLevel, String cmd, String params, WebView webView) {
   
        CommandDispatcher.getInstance().exec(context, commandLevel, cmd, params, webView, getDispatcherCallBack());
    }

可以看到在这个里面需要去调命令分发:

 public void exec(Context context, int commandLevel, String cmd, String params, WebView webView,
                     DispatcherCallBack dispatcherCallBack) {
   
        Log.i("CommandDispatcher", "command: " + cmd + " params: " + params);
        try {
   
            if (CommandsManager.getInstance().checkHitLocalCommand(commandLevel, cmd)) {
   
                execLocalCommand(context, commandLevel, cmd, params, webView, dispatcherCallBack);
            } else {
   
                execRemoteCommand(context, commandLevel, cmd, params, webView, dispatcherCallBack);
            }
        } catch (Exception e) {
   
            Log.e("CommandDispatcher", "Command exec error!!!!", e);
        }
    }

首先会判断是否是在本地需要处理的命令,不是的话就去执行远程命令,因为webView通信有可能是多进程的,所以这里把命令分为了3个等级:

  1. LocalCommands (本地命令)
  2. BaseLevelCommands (基础的一些命令)
  3. AccountLevelCommands (与账户相关,带有头信息的)

这3个等级,是在CommandsManager里面管理的,这个里面有注册命令的方法registerCommand, 与获取命令的方法findAndExecRemoteCommand(寻找远程要执行的命令), findAndExecLocalCommnad(寻找本地要执行的命令),这些命令有一个统一的接口:

public interface Command {
   
    String COMMAND_UPDATE_TITLE = "xiangxue_webview_update_title";
    String COMMAND_UPDATE_TITLE_PARAMS_TITLE = "xiangxue_webview_update_title_params_title";

    String name();

    void exec(Context context, Map params, ResultBack resultBack);
}

而这些命令是被Commands这个命令集合所分类管理的:

public abstract class Commands {
   

    private HashMap<String, Command> commands;

    abstract int getCommandLevel();

    public HashMap<String, Command> getCommands() {
   
        return commands;
    }

    public Commands() {
   
        commands = new HashMap<>();
    }

    protected void registerCommand(Command command) {
   
        commands.put(command.name(), command);
    }
}

可以看到这是一个抽象的,它的实现就是刚才说的那3个等级的命令集,它被管理在CommandsManager里面:

public class CommandsManager {
   

    private static CommandsManager instance;

    private LocalCommands localCommands;
    private BaseLevelCommands baseLevelCommands;
    private AccountLevelCommands accountLevelCommands;

    private CommandsManager() {
   
        localCommands = new LocalCommands();
        baseLevelCommands = new BaseLevelCommands();
        accountLevelCommands = new AccountLevelCommands();
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值