x5_webview 0.2.2

  • Readme
  • Changelog
  • Example
  • Installing
  • 80

x5_webview pub package #

一个基于腾讯x5引擎的webview的flutter插件,暂时只支持android使用

x5内核介绍 #

x5内核,腾讯为改善移动端web体验的一种内核架构。加载更快,更省流量,视频播放优化,文件助手等等

快速集成 #

pub package

pub地址

pubspec.yaml文件添加

dependencies:
  x5_webview: ^x.x.x //最新版本见上方

初始化x5。(安卓6.0+需在init之前请求动态权限,可以使用permission_handler,详情见example/lib/main.dart)

var isOk = await X5Sdk.init();
print(isOk ? "X5内核成功加载" : "X5内核加载失败");

如果你只是想要简单的展示web页面,可使用以下代码直接打开一个webActivity, 性能更佳(推荐使用,视频播放也可以这个api)

X5Sdk.openWebActivity("https://www.baidu.com",title: "web页面");

使用TBSPlayer直接全屏播放视频(screenMode自行测试,103横屏 104竖屏,官方默认使用102第一次点击全屏无反应)

    var isOk = await X5Sdk.openVideo(
    "https://ifeng.com-l-ifeng.com/20180528/7391_46b6cf3b/index.m3u8",screenMode: 102);

打开本地文件(格式支持较多,视频音频图片办公文档压缩包等等,支持文件详情)

var errorMsg = await X5Sdk.openFile("/sdcard/download/FileList.xlsx");
print(errorMsg);

使用内嵌webview(可能会有些bug) #

return Scaffold(
      appBar: AppBar(
        title: Text("X5WebView示例"),
      ),
      body: defaultTargetPlatform == TargetPlatform.android
          ? X5WebView(
              url: "http://debugtbs.qq.com",
              javaScriptEnabled: true,
              onWebViewCreated: (control) {
                _controller = control;
              },
              onPageFinished: () async {
                var url = await _controller.currentUrl();
                print(url);
                var body = await _controller
                    .evaluateJavascript('document.body.innerHTML');
                print(body);
              },
            )
          :
          //可替换为其他已实现ios webview,此处使用webview_flutter
          WebView(
              initialUrl: "https://www.baidu.com",
              javascriptMode: JavascriptMode.unrestricted,
              onWebViewCreated: (control) {
                _otherController = control;
                var body = _otherController
                    .evaluateJavascript('document.body.innerHTML');
                print(body);
              },
            ),
    );

内嵌webview js与flutter互调

  • flutter调用js
var body = await _controller.evaluateJavascript("document.body.innerHTML");
  • js调用flutter
     X5WebView(
        ...
        javascriptChannels: JavascriptChannels(
            ["X5Web", "Toast"], (name, data) {
          switch (name) {
            ...
          }
        }))
  • js代码
X5Web.postMessage("XXX")
Toast.postMessage("YYY")

打开本地html文件(使用assets文件,内嵌webview同理) #

var fileS = await rootBundle.loadString("assets/index.html");
var url = Uri.dataFromString(fileS,
                          mimeType: 'text/html',
                          encoding: Encoding.getByName('utf-8'))
                      .toString();
X5Sdk.openWebActivity(url, title: "本地html示例");

注意事项 #

  • 该插件暂时只支持Android手机,IOS会使用无效。ios可使用webview_flutter或其他已实现IOS WXWebView插件

  • 一般手机安装了QQ,微信,QQ浏览器等软件,手机里自动会有X5内核,如果没有X5内核会在wifi下自动下载,X5内核没有加载成功会自动使用系统内核官网说明。详细配置可用手机打开以下链接查看X5内核的详情

      http://debugtbs.qq.com
    
  • 请使用真机测试,模拟器可能不能正常显示

  • 如果测试正常,打包后不能加载,可以尝试使用android studio打开android目录直接打包apk。

  • android9.0版本webview联不了网在manifest添加

      <application
          ...
          android:usesCleartextTraffic="true">
      </application>
    
  • android7.0版本打开文件需要在manifest的application内添加(xml文件已在插件内,无需自己创建)

            <!--        不使用androidx 请用android:name="android.support.v4.content.FileProvider"-->    
          <provider
              android:name="androidx.core.content.FileProvider"
              android:authorities="${applicationId}"
              android:exported="false"
              android:grantUriPermissions="true">
              <meta-data
                  android:name="android.support.FILE_PROVIDER_PATHS"
                  android:resource="@xml/x5webview_file_paths" />
          </provider>  
    
  • X5Sdk.openWebActivity actionbar颜色自定义

    //1.
    implementation "androidx.appcompat:appcompat:1.1.0"
    
    //2.
      <style name="AppTheme" parent="ThemeOverlay.AppCompat.Dark">
          <!-- Customize your theme here. -->
          <item name="colorPrimary">#2196F3</item>
          <item name="colorPrimaryDark">#1976D2</item>
          <item name="colorAccent">#FF4081</item>
          <item name="windowNoTitle">false</item>
          <item name="windowActionBar">true</item>
      </style>
    
    //3.
    <application
          ...
          android:theme="@style/AppTheme">
    
    
  • 有比较急的问题可以加我QQ:793710663

示例程序下载(密码:123456) #

apk下载

二维码

0.2.2 #

  • X5WebviewActivity新增header和url拦截
  • X5WebView addJavascriptChannels变更
  • demo增加动态权限、actionBar样式修改以及内核状态查看

0.2.1 #

  • 兼容新旧两种插件api(详情见manifest和MainActivity的注释)

0.2.0 #

  • kotlin版本和gradle版本升级
  • x5sdk升级,使用gradle集成sdk,去除so文件。支持64位手机(无需繁琐操作)

0.1.5 #

  • 增加本地html加载示例
  • sdk升级,添加文件权限
  • 修复部分bug

0.1.4 #

  • 增加文件打开功能
  • 内嵌webview增加接口isX5WebViewLoadSuccess

0.1.3 #

  • actionBar获取异常处理
  • 增加js调用flutter功能
  • 内核增加下载安装监听

0.1.2 #

  • 修复编译出错的问题

0.1.1 #

  • 调整示例app,修复loadUrl报错等问题

0.1.0 #

  • 修改部分代码,提升pub分数

0.0.1 #

  • 集成android x5内核webview

example/lib/main.dart

import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:x5_webview/x5_sdk.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';

import 'demo.dart';

import 'package:dio/dio.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: HomePage(),theme: ThemeData(primarySwatch: Colors.blue),);
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  var crashInfo;
  bool isLoadOk=false;
  @override
  void initState() {
    super.initState();
    loadX5();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Plugin example app'),
      ),
      body: Center(
        child: ListView(
          children: <Widget>[
            RaisedButton(
                onPressed: () async {
                  X5Sdk.openWebActivity("http://debugtbs.qq.com",
                      title: "X5内核信息");
                },
                child: Text("查看X5内核信息")),
            RaisedButton(
                onPressed: () async {
                  var canUseTbsPlayer = await X5Sdk.canUseTbsPlayer();
                  if (canUseTbsPlayer) {
                    showInputDialog(
                        onConfirm: (url) async {
                          await X5Sdk.openVideo(url, screenMode: 102);
                        },
                        defaultText:
                            "https://youku.com-l-youku.com/20181221/5625_d9733a43/index.m3u8");
                  } else {
                    print("x5Video不可用");
                  }
                },
                child: Text("x5video直接播放视频")),
            RaisedButton(
                onPressed: () async {
                  showDialog(
                      context: context,
                      builder: (context) {
                        return AlertDialog(
                          title: Text("X5Sdk打开本地文件示例"),
                          content: Text("请先下载再打开"),
                          actions: <Widget>[
                            FlatButton(
                              onPressed: () async {
                                Navigator.pop(context);
                              },
                              child: Text("取消"),
                            ),
                            FlatButton(
                              onPressed: () async {
                                try {
                                  showDialog(
                                      context: context,
                                      barrierDismissible: false,
                                      builder: (context) {
                                        return AlertDialog(
                                          content: Column(
                                            mainAxisSize: MainAxisSize.min,
                                            children: <Widget>[
                                              CircularProgressIndicator(),
                                              Padding(
                                                padding:
                                                    EdgeInsets.only(top: 20),
                                              ),
                                              Text("等待下载")
                                            ],
                                          ),
                                        );
                                      });
                                  var dir = await getExternalStorageDirectory();
                                  print(await getExternalStorageDirectory());
                                  print(await getApplicationSupportDirectory());
                                  print(
                                      await getApplicationDocumentsDirectory());
                                  var response = await Dio().download(
                                      "http://lc-QMTBhNKI.cn-n1.lcfile.com/fc441aa8ff4738cc3f85/FileList.xlsx",
                                      "${dir.path}/FileList.xlsx");
                                  print(response.data);
                                  Navigator.pop(context);
                                } on DioError catch (e) {
                                  Navigator.pop(context);
                                  print(e.message);
                                }
                              },
                              child: Text("下载"),
                            ),
                            FlatButton(
                              onPressed: () async {
                                var dir = await getExternalStorageDirectory();
                                print(dir);
                                var msg = await X5Sdk.openFile(
                                    "${dir.path}/FileList.xlsx",style: "1",topBarBgColor: "#2196F3");
                                print(msg);
                              },
                              child: Text("打开"),
                            )
                          ],
                        );
                      });
                },
                child: Text("x5sdk打开本地文件示例")),
            RaisedButton(
                onPressed: () async {
//                                          Navigator.of(context).push(
//                            CupertinoPageRoute(builder: (BuildContext context) {
//                              return DemoWebViewPage("http://bin.amazeui.org/tizayo");
//                            }));

                  showInputDialog(
                      onConfirm: (url) {
                        Navigator.of(context).push(
                            CupertinoPageRoute(builder: (BuildContext context) {
                          return DemoWebViewPage(url);
                        }));
                      },
                      defaultText: "http://bin.amazeui.org/tizayo");
                },
                child: Text("flutter内嵌x5webview")),
            RaisedButton(
                onPressed: () async {
                  showInputDialog(
                      onConfirm: (url){
                        openUrl(url);
                      },
                      defaultText: "https://www.baidu.com");
                },
                child: Text("x5webviewActivity")),
            RaisedButton(
                onPressed: () async {
                  var fileHtmlContents =
                      await rootBundle.loadString("assets/index.html");
                  var url = Uri.dataFromString(fileHtmlContents,
                          mimeType: 'text/html',
                          encoding: Encoding.getByName('utf-8'))
                      .toString();

                  await X5Sdk.openWebActivity(url, title: "本地html示例");
                },
                child: Text("本地html")),
            RaisedButton(
                onPressed: () async {
                  loadX5();
                },
                child: Text("重新加载内核")),
            Text("内核状态:\n${crashInfo==null ? "未加载": isLoadOk? "加载成功---\n"+crashInfo.toString(): "加载失败---\n"+crashInfo.toString()}")
          ],
        ),
      ),
    );
  }

  void showInputDialog(
      {@required ConfirmCallBack onConfirm, String defaultText = ""}) {
    final _controller = TextEditingController(text: defaultText);
    showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            title: Text("输入链接测试"),
            content: TextField(
              controller: _controller,
            ),
            actions: <Widget>[
              FlatButton(
                  onPressed: () {
                    Navigator.pop(context);
                  },
                  child: Text("取消")),
              FlatButton(
                  onPressed: () async {
                    Navigator.pop(context);
                    onConfirm(_controller.text);
                  },
                  child: Text("跳转"))
            ],
          );
        });
  }

  var isLoad = false;

  void loadX5() async {
    if (isLoad) {
      showMsg("你已经加载过x5内核了,如果需要重新加载,请重启");
      return;
    }

    //请求动态权限,6.0安卓及以上必有
    Map<Permission, PermissionStatus> statuses = await [
      Permission.phone,
      Permission.storage,
    ].request();
    //判断权限
    if (!(statuses[Permission.phone].isGranted &&
        statuses[Permission.storage].isGranted)) {
      showDialog(
          context: context,
          builder: (context) {
            return AlertDialog(
              content: Text("请同意所有权限后再尝试加载X5"),
              actions: [
                FlatButton(
                    onPressed: () {
                      Navigator.pop(context);
                    },
                    child: Text("取消")),
                FlatButton(
                    onPressed: () {
                      Navigator.pop(context);
                      loadX5();
                    },
                    child: Text("再次加载")),
                FlatButton(
                    onPressed: () {
                      Navigator.pop(context);
                      openAppSettings();
                    },
                    child: Text("打开设置页面")),
              ],
            );
          });
      return;
    }

    //没有x5内核,是否在非wifi模式下载内核。默认false
    await X5Sdk.setDownloadWithoutWifi(true);

    //内核下载安装监听
    await X5Sdk.setX5SdkListener(X5SdkListener(onInstallFinish: () {
      print("X5内核安装完成");
    }, onDownloadFinish: () {
      print("X5内核下载完成");
    }, onDownloadProgress: (int progress) {
      print("X5内核下载中---$progress%");
    }));
    print("----开始加载内核----");
    var isOk = await X5Sdk.init();
    print(isOk ? "X5内核成功加载" : "X5内核加载失败");

    var x5CrashInfo = await X5Sdk.getCrashInfo();
    print(x5CrashInfo);
    if(isOk){
      x5CrashInfo="tbs_core_version" + x5CrashInfo.split("tbs_core_version")[1];
    }
    setState(() {
      isLoadOk=isOk;
      crashInfo = x5CrashInfo;
    });

    isLoad = true;
  }

  void showMsg(String msg) {
    showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            content: Text(msg),
            actions: [
              FlatButton(
                  onPressed: () {
                    Navigator.pop(context);
                  },
                  child: Text("我知道了"))
            ],
          );
        });
  }

  void openUrl(String url) {
    X5Sdk.openWebActivity(url, title: "web页面",callback: (url,headers){
      print("拦截到url================$url");
      print("headers================$headers");
      //可以递归无限套娃
      openUrl(url);
    });
  }
}

typedef ConfirmCallBack = Function(String url);

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  x5_webview: ^0.2.2

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:x5_webview/x5_webview.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
61
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
80
Learn more about scoring.

We analyzed this package on May 24, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.1
  • pana: 0.13.8-dev
  • Flutter: 1.17.0

Health suggestions

Format lib/x5_webview.dart.

Run flutter format to format lib/x5_webview.dart.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.12
meta 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test