
Webview.png
1.webview的組成由哪幾部分組成
答:由四個(gè)部分組成
1.WebSettings 負(fù)責(zé)webview的設(shè)置部分
2.WebViewClient 負(fù)責(zé)webview的生命周期回調(diào)
3.WebViewChromeClient 與Js交互 以及內(nèi)核部分調(diào)度 如彈出彈窗等
4.JavaScriptInstance 負(fù)責(zé)js與native的交互部分
2.為什么打造成組件以及如何實(shí)現(xiàn)的組件化?
打造成組件是為了方便不同的項(xiàng)目導(dǎo)入,實(shí)現(xiàn)方法采用引入AutoService通過(guò)依賴倒置原則 由接口定義方法。
定義接口與實(shí)現(xiàn)
public interface IWebViewService {
void startWebViewActivity(Context context, String url,String title,boolean isShowActionBar);
Fragment getWebViewFragment(String url,boolean needNativeRefresh);
void startLocalPage(Context context);
}
@AutoService({IWebViewService.class})
public class WebViewServiceImpl implements IWebViewService {
@Override
public void startWebViewActivity(Context context, String url, String title,boolean isShowActionBar) {
....
}
@Override
public Fragment getWebViewFragment(String url,boolean needNativeRefresh) {
` ...
}
@Override
public void startLocalPage(Context context) {
...
}
}
找到組件,通過(guò)serviceLoader
IWebViewService webImpl = ServiceLoader.load(IWebViewService.class).iterator().next();
webImpl.startLocalPage(...)
2.為什么要使用獨(dú)立進(jìn)程開(kāi)啟webview?
1.webview本身占用的內(nèi)存比較大 容易在性能較差的機(jī)型上導(dǎo)致oom
2.webview需要兼容多種網(wǎng)頁(yè) 新老網(wǎng)頁(yè)格式都有 使用獨(dú)立進(jìn)程可以避免webview加載崩潰導(dǎo)致的app主進(jìn)程崩潰引發(fā)crash
3.進(jìn)程之間的通信與調(diào)度你是如何處理的?
不同進(jìn)程之間的通信是通過(guò)實(shí)現(xiàn)aidl來(lái)完成的
開(kāi)啟單獨(dú)進(jìn)程,在所在的activity下設(shè)置process屬性
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.chenx.webview">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application android:usesCleartextTraffic="true">
<activity android:name=".webviewprocess.WebViewActivity"
android:process=":myWebView"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"></activity>
<service android:name=".mainprocess.MainProcessCommandService"/>
</application>
</manifest>
aidl創(chuàng)建與使用
//創(chuàng)建
// IWebviewProcessToMainProcess.aidl
package com.chenx.webview;
// Declare any non-default types here with import statements
import com.chenx.webview.IMainProcessToWebviewProcessInterface;
interface IWebviewProcessToMainProcess {
void handleWebCommand(String commandName,String jsinParams,IMainProcessToWebviewProcessInterface callback);
}
//實(shí)現(xiàn)
... extends IWebviewProcessToMainProcess.Stub{
@override
void handleWebCommand(String commandName,String jsinParams,IMainProcessToWebviewProcessInterface callback){
}
}
Command命令定義
public interface Command {
//命令名稱
String name();
//命令處理的行為
void execute(Map parameters, IMainProcessToWebviewProcessInterface callback);
}
命令實(shí)現(xiàn):
@AutoService({Command.class})
public class ToastCommand implements Command {
@Override
public String name() {
return "showToast";
}
@Override
public void execute(Map parameters, IMainProcessToWebviewProcessInterface callback) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(()->{
Toast.makeText(BaseApplication.sApplication, String.valueOf(parameters.get("message")), Toast.LENGTH_SHORT).show();
});
}
}
調(diào)度器與分發(fā)器
分發(fā)器
public class WebViewProcessCommandDispatcher implements ServiceConnection {
private static WebViewProcessCommandDispatcher sInstance;
private IWebviewProcessToMainProcess iWebviewProcessToMainProcess;
public static WebViewProcessCommandDispatcher getsInstance() {
//獲取分發(fā)器單例實(shí)例
return sInstance;
}
//創(chuàng)建Aidl連接
public void initAidlConnection(){
Intent intent = new Intent(BaseApplication.sApplication, MainProcessCommandService.class);
BaseApplication.sApplication.bindService(intent,this, Context.BIND_AUTO_CREATE);
}
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
iWebviewProcessToMainProcess = IWebviewProcessToMainProcess.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
iWebviewProcessToMainProcess = null;
initAidlConnection();
}
@Override
public void onBindingDied(ComponentName name) {
iWebviewProcessToMainProcess = null;
initAidlConnection();
}
//處理命令分發(fā)給調(diào)度器
public void executeCommand(String commandName, String params, BaseWebView webView){
if(iWebviewProcessToMainProcess !=null){
try {
//aidl實(shí)例 分發(fā)命令
iWebviewProcessToMainProcess.handleWebCommand(commandName, params,
new IMainProcessToWebviewProcessInterface.Stub() {
@Override
public void onResult(String callbackname, String response) throws RemoteException {
webView.handleCallback(callbackname, response);
}
});
} catch (RemoteException e) {
e.printStackTrace();
}
}else{
Log.e(BaseWebView.TAG,"iWebviewProcessToMainProcess 未綁定===");
}
}
調(diào)度器
public class MainProcessCommandManager extends IWebviewProcessToMainProcess.Stub{
private static final String TAG = "MainProcess";
public static MainProcessCommandManager sInstance;
private static Map<String, Command> mCommands = new HashMap<>();
public static MainProcessCommandManager getInstance(){
//調(diào)度器實(shí)例
return sInstance;
}
public MainProcessCommandManager() {
//自動(dòng)注冊(cè)命令
ServiceLoader<Command> serviceLoader = ServiceLoader.load(Command.class);
for (Command command:serviceLoader) {
if(!mCommands.containsKey(command.name())){
mCommands.put(command.name(),command);
}
}
}
@Override
public void handleWebCommand(String commandName, String jsinParams, IMainProcessToWebviewProcessInterface callback) throws RemoteException {
//轉(zhuǎn)map 調(diào)度命令
executeCommand(commandName,new Gson().fromJson(jsinParams, Map.class),callback);
}
private void executeCommand(String commandName, Map params,IMainProcessToWebviewProcessInterface callback) {
Log.d(TAG,"commandName:"+commandName);
//執(zhí)行命令
mCommands.get(commandName).execute(params,callback);
}
}
}
回調(diào)
通過(guò)回向aidl調(diào)用會(huì)webprocess
iWebviewProcessToMainProcess.handleWebCommand(commandName, params, new IMainProcessToWebviewProcessInterface.Stub() {
@Override
public void onResult(String callbackname, String response) throws RemoteException {
Log.d("ResultNative","回傳Native結(jié)果"+callbackname+"<"+response);
webView.handleCallback(callbackname, response);
}
});
//調(diào)用evaluateJavascript注入js
public void handleCallback(String callbackname, String response) {
if(!TextUtils.isEmpty(callbackname)&&!TextUtils.isEmpty(response)){
String jscode = "javascript:xiangxuejs.callback('"+callbackname+"',"+response+")";
Log.d("callBackData",callbackname+":"+response);
post(new Runnable() {
@Override
public void run() {
evaluateJavascript(jscode,null);
}
});
}
}