В настоящее время мобильная кроссплатформенная разработка, как важная часть мобильной разработки, является навыком, которым мобильные разработчики должны овладеть, и важным средством самосовершенствования. Как кроссплатформенное техническое решение, запущенное Google, Flutter имеет много преимуществ и используется или используется разработчиками при разработке мобильных приложений. В прошлом 2019 году я видел, как все больше и больше компаний и частных лиц начинают использовать Flutter для разработки кроссплатформенных приложений.Для разработки мобильных приложений Flutter может удовлетворить практически все потребности в развитии бизнеса, поэтому пришло время изучить Flutter.
Как мы все знаем, при использовании Flutter для разработки проекта загрузка страницы H5 неизбежна, а для открытия страницы H5 в мобильной разработке требуется компонент WebView. В то же время для обмена данными со страницами H5 иногда необходимо использовать JSBridge для реализации связи между клиентом и H5. Кроме того, гибридная модель разработки также требует частого взаимодействия между Webview и JS.
Установить
В этой статье используется официальный компонент Flutter webview_flutter, последняя версия которого — 0.3.19+9. Перед использованием вам необходимо добавить зависимость плагина webview_flutter, как показано ниже.
webview_flutter: 0.3.19+9
Затем используйте пакеты Thurter Get Command, чтобы потянуть плагин локально и оставаться зависимым. Поскольку сеть загружается с помощью WebView, вам также нужно добавлять привилегии сети на Android. Откройте каталог Android / App / SRC / Main / AndroidManifest.xml, затем добавьте следующий код.
<uses-permission android:name="android.permission.INTERNET"/>
Поскольку Https включен по умолчанию в iOS версии 9.0, для запуска веб-страниц Http вам необходимо добавить следующий код в файл ios/Runner/Info.plist.
<key>io.flutter.embedded_views_preview</key>
<string>YES</string>
основное использование
Откройте исходный код компонента WebView, конструктор компонента WebView выглядит следующим образом.
const WebView({
Key key,
this.onWebViewCreated,
this.initialUrl,
this.javascriptMode = JavascriptMode.disabled,
this.javascriptChannels,
this.navigationDelegate,
this.gestureRecognizers,
this.onPageStarted,
this.onPageFinished,
this.debuggingEnabled = false,
this.gestureNavigationEnabled = false,
this.userAgent,
this.initialMediaPlaybackPolicy =
AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,
}) : assert(javascriptMode != null),
assert(initialMediaPlaybackPolicy != null),
super(key: key);
Среди них наиболее распространенные атрибуты имеют следующие значения:
- onWebViewCreated: вызывается после создания WebView, будет вызываться только один раз;
- initialUrl: URL начальной загрузки;
- javascriptMode: режим выполнения JS (разрешено ли выполнение JS);
- javascriptChannels: канал для связи JS и Flutter;
- navigationDelegate: делегат маршрутизации (вы можете реализовать JS-вызов Flutter, перехватив URL-адрес здесь);
- распознавание жестов: прослушиватель жестов;
- OnPagefineed: Callback Когда WebView загружен. Импорт «Дартс: Async»;
При использовании Webview для загрузки веб-страниц часто необходимо взаимодействовать с JS, то есть JS вызывает Flutter, а Flutter вызывает JS. Для Flutter относительно просто вызвать JS, просто вызовите функцию _controller.evaluateJavascript() напрямую. JS вызывает Flutter чуть более раздражающим, потому что каталог javascriptChannels поддерживает только строковые типы, а метод JS исправлен, то есть можно использовать только метод postMessage, что не является проблемой для iOS, но для Android есть проблема, конечно, это также может быть достигнуто путем изменения исходного кода.
JS вызывает флаттер
путь javascriptChannels
Метод JavaScriptchannels также является рекомендуемым способом, который в основном используется для JS для передачи данных для трепетания. Например, есть следующий код JS.
<button onclick="callFlutter()">callFlutter</button>
function callFlutter(){
Toast.postMessage("JS调用了Flutter");
}
Использование метода postMessage Toast — это определенное имя.При принятии нужно использовать это имя для получения.Код на стороне Flutter выглядит следующим образом.
WebView(
javascriptChannels: <JavascriptChannel>[
_alertJavascriptChannel(context),
].toSet(),
)
JavascriptChannel _alertJavascriptChannel(BuildContext context) {
return JavascriptChannel(
name: 'Toast',
onMessageReceived: (JavascriptMessage message) {
showToast(message.message);
});
}
navigationDelegate
Кроме того, есть еще один способ — navigationDelegate, который в основном перехватывает при загрузке веб-страниц, например следующий протокол JS.
document.location = "js://webview?arg1=111&args2=222";
Соответствующий код Flutter выглядит следующим образом.
navigationDelegate: (NavigationRequest request) {
if (request.url.startsWith('js://webview')) {
showToast('JS调用了Flutter By navigationDelegate');
print('blocking navigation to $request}');
Navigator.push(context,
new MaterialPageRoute(builder: (context) => new testNav()));
return NavigationDecision.prevent;
}
print('allowing navigation to $request');
return NavigationDecision.navigate; //必须有
},
Среди них NavigationDecision.prevent означает запрет замены маршрута, а NavigationDecision.navigate означает разрешение замены маршрута.
JSBridge
Кроме того, мы также можем сами разработать JSBridge и установить набор общих спецификаций. Во-первых, вам нужно разработать соглашение с H5 для создания Модели.
class JsBridge {
String method; // 方法名
Map data; // 传递数据
Function success; // 执行成功回调
Function error; // 执行失败回调
JsBridge(this.method, this.data, this.success, this.error);
/// jsonEncode方法中会调用实体类的这个方法。如果实体类中没有这个方法,会报错。
Map toJson() {
Map map = new Map();
map["method"] = this.method;
map["data"] = this.data;
map["success"] = this.success;
map["error"] = this.error;
return map;
}
static JsBridge fromMap(Map<String, dynamic> map) {
JsBridge jsonModel = new JsBridge(map['method'], map['data'], map['success'], map['error']);
return jsonModel;
}
@override
String toString() {
return "JsBridge: {method: $method, data: $data, success: $success, error: $error}";
}
}
Затем H5 метод полученной внутренней обработки. Например, клиент предоставляет интерфейс OpenWechatapp App Micro-канал, открытый для H5, как показано ниже.
class JsBridgeUtil {
/// 将json字符串转化成对象
static JsBridge parseJson(String jsonStr) {
JsBridge jsBridgeModel = JsBridge.fromMap(jsonDecode(jsonStr));
return jsBridgeModel;
}
/// 向H5开发接口调用
static executeMethod(context, JsBridge jsBridge) async{
if (jsBridge.method == 'openWeChatApp') {
/// 先检测是否已安装微信
bool _isWechatInstalled = await fluwx.isWeChatInstalled();
if (!_isWechatInstalled) {
toast.show(context, '您没有安装微信');
jsBridge.error?.call();
return;
}
fluwx.openWeChatApp();
jsBridge.success?.call();
}
}
}
Чтобы сделать наш инкапсулированный WebView более общим, мы можем инкапсулировать WebView, как показано ниже.
final String url;
final String title;
WebViewController webViewController; // 添加一个controller
final PrivacyProtocolDialog privacyProtocolDialog;
Webview({Key key, this.url, this.title = '', this.privacyProtocolDialog})
: super(key: key);
@override
WebViewState createState() => WebViewState();
}
class WebViewState extends State<Webview> {
bool isPhone = Adapter.isPhone();
JavascriptChannel _JsBridge(BuildContext context) => JavascriptChannel(
name: 'FoxApp', // 与h5 端的一致 不然收不到消息
onMessageReceived: (JavascriptMessage msg) async{
String jsonStr = msg.message;
JsBridgeUtil.executeMethod(JsBridgeUtil.parseJson(jsonStr));
});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: isPhone ? Colors.white : Color(Config.foxColors.bg),
appBar: AppBar(
backgroundColor: isPhone ? null : Color(Config.foxColors.bg),
leading: AppIcon(Config.foxImages.backGreyUrl,
callback: (){
Navigator.of(context).pop(true);
if (widget.privacyProtocolDialog != null) { // 解决切换页面时弹框显示异常问题
privacyProtocolDialog.show(context);
}
}),
title: Text(widget.title),
centerTitle: true,
elevation: 0,
),
body: StoreConnector<AppState, UserState>(
converter: (store) => store.state.userState,
builder: (context, userState) {
return WebView(
initialUrl: widget.url,
userAgent:"Mozilla/5.0 FoxApp", // h5 可以通过navigator.userAgent判断当前环境
javascriptMode: JavascriptMode.unrestricted, // 启用 js交互,默认不启用JavascriptMode.disabled
javascriptChannels: <JavascriptChannel>[
_JsBridge(context) // 与h5 通信
].toSet(),
);
}),
);
}
}
Когда JS нужно вызвать Flutter, он может напрямую вызвать JsBridge, как показано ниже.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<script src="https://cdn.bootcss.com/jquery/2.0.1/jquery.js"></script>
<body>
coming baby!
<script>
var str = navigator.userAgent;
if (str.includes('FoxApp')) {
FoxApp.postMessage(JSON.stringify({method:"openWeChatApp"}));
} else {
$('body').html('<p>hello world</p>');
}
</script>
</body>
</html>
Если вы столкнулись с другими проблемами в процессе доступа, вы можете оставить сообщение в конце статьи!