Flutter-Webview组件处理Scheme协议

项目背景

之前我介绍过Flutter建立JsBridge用于webview与h5通信,有时候h5页面中需要唤醒其他应用的功能,通过约定的Scheme协议,比如weixin://,这时候就需要我们的Webview组件处理,否则就会出现net:ERR_UNKNOWN_URL-SCHEME的页面报错。

插件变更

上篇介绍Webview使用的文章,我用的是官方插件 webview_flutter,实际应用的时候,出现了个难以解决的bug,在华为mate30、android10环境下,h5的input元素调取手机系统键盘会失败,据我们测试,目前只发现在该手机型号、安卓系统下出现该问题,而华为客户占比很重,是必须要解决的,github上有类似的closed issue,推荐使用flutter_webview_plugin,所以就更改了webview插件,这两个插件评分都很高,提供的api类似,使用方法也相似,组件改造工作量很小。

组件改造

1、安装webview_flutter

 flutter_webview_plugin: ^0.3.10+1

2、 ios中在ios/Runner/Info.plist中添加

NSAppTransportSecurity

    NSAllowsArbitraryLoads
    
    NSAllowsArbitraryLoadsInWebContent
    

3、改造WebView组件

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:url_launcher/url_launcher.dart';

import '../configs/config.dart';
import '../utils/adapter.dart';
import '../utils/JsBridgeUtil.dart';
import '../widgets/AppIcon.dart';
import '../widgets/FixedSizeText.dart';

/// 与h5 端的一致 不然收不到消息
const String userAgent = 'FoxApp';

/// WebView页面
class Webview extends StatefulWidget {
  final String url;
  final String title;
  final VoidCallback backCallback;

  Webview({
    Key key,
    @required this.url,
    this.title = '',
    this.backCallback,
  }) : super(key: key);

  @override
  WebviewState createState() => WebviewState();
}

class WebviewState extends State {
  bool isPhone = Adapter.isPhone();
  final flutterWebViewPlugin = FlutterWebviewPlugin();

  final Set jsChannels = [
    JavascriptChannel(
        name: userAgent,
        onMessageReceived: (JavascriptMessage msg) {
          String jsonStr = msg.message;
          JsBridgeUtil.executeMethod(JsBridgeUtil.parseJson(jsonStr));
        }),
  ].toSet();

  // On urlChanged stream
  StreamSubscription _onUrlChanged;

  @override
  void initState() {
    super.initState();
    flutterWebViewPlugin.close();

    // Add a listener to on url changed
    _onUrlChanged =
        flutterWebViewPlugin.onUrlChanged.listen((String url) async {
      if (url.contains('weixin:') || url.contains('alipay:')) {
        await flutterWebViewPlugin.stopLoading();
        await flutterWebViewPlugin.goBack();
        if (await canLaunch(url)) {
          await launch(url);
        } else {
          throw 'Could not launch $url';
        }
      }
    });
  }

  @override
  void dispose() {
    _onUrlChanged.cancel();
    flutterWebViewPlugin.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: isPhone ? Colors.white : Color(Config.foxColors.bg),
      body: WebviewScaffold(
        appBar: AppBar(
          backgroundColor: isPhone ? null : Color(Config.foxColors.bg),
          leading: AppIcon(Config.foxImages.backGreyUrl, callback: () {
            flutterWebViewPlugin.close();
            Navigator.of(context).pop(true);
            widget.backCallback?.call();
          }),
          title: FixedSizeText(widget.title),
          centerTitle: true,
          elevation: 0,
        ),
        url: widget.url,
        userAgent: "Mozilla/5.0 $userAgent",
        // h5 可以通过navigator.userAgent判断当前环境
        javascriptChannels: jsChannels,
        mediaPlaybackRequiresUserGesture: false,
        withZoom: true,
        withLocalStorage: true,
        hidden: true,
      ),
    );
  }
}

测试同学提出了一个bug,跳转微信时,会偶现net:ERR_UNKNOWN_URL-SCHEME页面,这条issue也在讨论这个问题,https://github.com/fluttercommunity/flutter_webview_plugin/issues/43,本质是插件提供的功能不完善,没有提供拦截页面显示的方法,社区提出了一些解决方式。

/// 兼容android进入报错页
    _onStateChanged = flutterWebViewPlugin.onStateChanged
        .listen((WebViewStateChanged state) async {
      if (mounted) {
        if (state.url.startsWith('weixin:') &&
            state.type == WebViewState.abortLoad) {
          if (await canLaunch(state.url)) {
            await launch(state.url);
          } else {
            throw 'Could not launch ${state.url}';
          }
        }
      }
    });

你可能感兴趣的:(Flutter-Webview组件处理Scheme协议)