近期把原先的navite app用flutter重寫,原先app裡面有大量通過JsBridge與web互動的邏輯,換到flutter這邊之後發現沒用現成可用的第三方庫,然後自己寫了一個bridge_webview_flutter。
第三方依賴
在原先的webview裡面加上相關的邏輯和依賴
Android使用的是JsBridge
...
rootProject.allprojects {
repositories {
google()
jcenter()
maven { url 'https://jitpack.io' }
}
}
...
dependencies {
implementation 'androidx.annotation:annotation:1.0.0'
implementation 'androidx.webkit:webkit:1.0.0'
compile 'com.github.lzyzsd:jsbridge:1.0.4'
}
...
複製程式碼
iOS使用的是WebViewJavascriptBridge
...
s.dependency 'Flutter'
s.dependency 'WebViewJavascriptBridge'
...
複製程式碼
Navite與Flutter互動
通過MethodChannel進行互動
@override
Future<void> callHandler(String name, {dynamic data, BridgeCallBack onCallBack}) {
if (onCallBack != null) {
_bridgeCallBackMap[name] = onCallBack;
}
return _channel.invokeMethod("callHandler", {"name": name, "data": data});
}
@override
Future<void> registerHandler(String name, {dynamic response, BridgeCallBack onCallBack}) {
if (onCallBack != null) {
_bridgeCallBackMap[name] = onCallBack;
}
return _channel.invokeMethod("registerHandler", {"name": name, "response": response});
}
複製程式碼
使用一個map來儲存需要用到的回撥函式
iOS
- (void)registerHandler:(FlutterMethodCall *)call {
NSString *name = [call arguments][@"name"];
id response = [call arguments][@"response"];
if (name) {
__weak typeof(self) weakSelf = self;
[_bridge registerHandler:name handler:^(id data, WVJBResponseCallback responseCallback) {
NSDictionary *callback = @{
@"name": name,
@"data": data
};
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf->_channel invokeMethod:@"bridgeCallBack" arguments:[self dictionaryToJsonString:callback]];
if (response) {
if ([response isKindOfClass:[NSDictionary class]]) {
responseCallback([self dictionaryToJsonString:response]);
} else {
responseCallback(response);
}
}
}];
}
}
- (void)callHandler:(FlutterMethodCall *)call {
NSString *name = [call arguments][@"name"];
id data = [call arguments][@"data"];
if (name) {
__weak typeof(self) weakSelf = self;
[_bridge callHandler:name data:data responseCallback:^(id responseData) {
NSDictionary *callback = @{
@"name": name,
@"data": responseData
};
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf->_channel invokeMethod:@"bridgeCallBack" arguments:[self dictionaryToJsonString:callback]];
}];
}
}
複製程式碼
省略了一些配置程式碼,可以參考官方文件
Android
Android這邊需要把原先的InputAwareWebView
繼承BridgeWebView
然後再把原先的WebViewClient
替換成BridgeWebViewClient
webView.setWebViewClient(new BridgeWebViewClient(webView));
複製程式碼
private void registerHandler(MethodCall call) {
final Map<String, Object> map = (Map<String, Object>) call.arguments;
final String name = (String) map.get("name");
if (name != null) {
webView.registerHandler(name, new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
Object response = map.get("response");
if (response != null) {
if (response instanceof HashMap) {
JSONObject jsonObject = new JSONObject((Map) response);
function.onCallBack(jsonObject.toString());
} else {
function.onCallBack((String) response);
}
}
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("name", name);
jsonObject.put("data", data);
methodChannel.invokeMethod("bridgeCallBack", jsonObject.toString());
} catch (JSONException e) {
Log.e("JsBridge", "json error");
}
}
});
}
}
private void callHandler(MethodCall call) {
final Map<String, Object> map = (Map<String, Object>) call.arguments;
final String name = (String) map.get("name");
if (name != null) {
Object data = map.get("data");
String dataStr = "";
if (data != null) {
if (data instanceof Map) {
JSONObject jsonObject = new JSONObject((Map) data);
dataStr = jsonObject.toString();
} else {
dataStr = (String) data;
}
}
webView.callHandler(name, dataStr, new CallBackFunction() {
@Override
public void onCallBack(String data) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("name", name);
jsonObject.put("data", data);
methodChannel.invokeMethod("bridgeCallBack", jsonObject.toString());
} catch (JSONException e) {
Log.e("JsBridge", "json error");
}
}
});
}
}
複製程式碼
使用
通過flutter pub get
載入依賴
dependencies:
bridge_webview_flutter: ^0.1.1
複製程式碼
在onWebViewCreated
方法裡面通過webViewController
呼叫
...
body: Builder(builder: (BuildContext context) {
return WebView(
initialUrl: 'https://flutter.dev',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
webViewController.registerHandler("methodName", response: "r1", onCallBack: (callBackData) {
print(callBackData.name); // handler name
print(callBackData.data); // callback data ({'param': '1'})
});
webViewController.callHandler("methodName", data: "sendData", onCallBack: (callBackData) {
print(callBackData.name); // handler name
print(callBackData.data); // callback data (r2)
});
},
onPageStarted: (String url) {
print('Page started loading: $url');
},
onPageFinished: (String url) {
print('Page finished loading: $url');
},
gestureNavigationEnabled: true,
);
}
...
複製程式碼