项目背景

项目需要从钉钉微应用跳转 WPS 打开 word 文档,但是 WPS 只提供了 StartActivity 方式携带参数跳转应用,deeplink 只能打开应用,而钉钉微应用只支持 deeplink ,所以需要搭建一个中间跳转的app工具。

Flutter

Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。

flutter使用dart语言,是将来谷歌新操作系统 Fuchsia 的主要构建方式,组件使用响应式框架构建,使用组件构建 UI ,组件可以改变状态,提供热加载,最大的特点是同时在iOS和Android系统中开发应用,支持混合开发。

获取 deeplink 路径

在flutter应用中导入 uni_links 包,接收deeplink:

在 pubspec.yaml 文件 dependencies 下增加 uni_links: ^0.1.4 ,记得执行 flutter packages get

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class  extends State<FirstPage> {

  void initState() {
...
getInitialUri().then((Uri url) {
print('URL received: $url');
if (url != null && url.scheme == 'gsoft') {
map.addAll(url.queryParameters);
}
});
...
super.initState();
}
...
}

执行 getInitialUri 方法可以拿到 deeplink 的路径,获取传递的参数。

通过 StartActivity 方式启动WPS

flutter应用与原生之间交互需要通过插件模式:

定义 plugin,两边 plugin 名需要一致

flutter端:

1
2
3
4
5
6
class  extends State<FirstPage> {
...
const demoPlugin = const MethodChannel('wps.plugin');
demoPlugin.invokeMethod('interaction', map);
...
}

android端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
public class MainActivity extends FlutterActivity {

    private static final String CHANNEL = "wps.plugin";

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
if (call.method.equals("interaction")) {
String fileUrl = call.argument("fileUrl");
Bundle bundle = new Bundle();
//打开文档参数-打开模式
Object openMode = call.argument("OpenMode");
if (openMode != null) {
bundle.putString(WpsModel.OPEN_MODE, String.valueOf(openMode));
} //打开文档参数-打开直接进入编辑模式
Object editMode = call.argument("EditMode");
if (editMode != null) {
bundle.putBoolean("Edit Mode", Boolean.valueOf(editMode.toString()));
} //文档记录-删除使用记录
Object clearTrace = call.argument("ClearTrace");
if (clearTrace != null) {
bundle.putBoolean("ClearTrace", Boolean.valueOf(clearTrace.toString()));
} //文档初始化参数-自动跳转
Object autoJump = call.argument("AutoJump");
if (autoJump != null) {
bundle.putBoolean("AutoJump", Boolean.valueOf(autoJump.toString()));
} //修订相关参数-打开文档是否显示修订批注面板
Object showReviewingPaneRightDefault = call.argument("ShowReviewingPaneRightDefault");
if (showReviewingPaneRightDefault != null) {
bundle.putBoolean("ShowReviewingPaneRightDefault", Boolean.valueOf(showReviewingPaneRightDefault.toString()));
} //修订相关参数-修订模式打开文档
Object enterReviseMode = call.argument("EnterReviseMode");
if (enterReviseMode != null) {
bundle.putBoolean("EnterReviseMode", 大专栏  flutter实践 - plsyan class="keyword">Boolean.valueOf(enterReviseMode.toString()));
} //水印相关参数-设置水印文字内容
Object waterMaskText = call.argument("WaterMaskText");
if (waterMaskText != null) {
bundle.putString("WaterMaskText", String.valueOf(waterMaskText));
} //批注-批注的作者
Object userName = call.argument("UserName");
if (userName != null) {
bundle.putString("UserName", String.valueOf(userName));
} //文件保存时发送广播
bundle.putBoolean("SendSaveBroad", true); Intent intent = new Intent();
File file = new File(fileUrl); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(MainActivity.this,
BuildConfig.APPLICATION_ID + ".provider", file);
intent.setData(contentUri);
intent.putExtras(bundle); intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setClassName(WpsModel.PackageName.PRO, WpsModel.ClassName.NORMAL);
MainActivity.this.startActivity(intent); result.success("success");
} else {
result.notImplemented();
}
}
}); GeneratedPluginRegistrant.registerWith(this);
} }

WPS保存文件操作后广播

原生安卓端接收 WPS 广播后,传递给 flutter 处理。

android端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
private static final String SAVED_CHANNEL = "saved.wps.plugin";
...
//接收wps广播
new EventChannel(getFlutterView(), SAVED_CHANNEL)
.setStreamHandler(new EventChannel.StreamHandler() {
private BroadcastReceiver savedReceiver; @Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
savedReceiver = createSavedReceiver(eventSink);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("cn.wps.moffice.broadcast.AfterSaved");
registerReceiver(savedReceiver, intentFilter);
} @Override
public void onCancel(Object o) {
unregisterReceiver(savedReceiver);
savedReceiver = null;
}
});
... private BroadcastReceiver createSavedReceiver(final EventChannel.EventSink events) {
return new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getBooleanExtra(SAVE_AS, false)) {
events.success(intent.getStringExtra("CurrentPath"));
}
}
};
}

flutter端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  static const fromAndroidPlugin = const EventChannel('saved.wps.plugin');

...
void _fromAndroidPlugin() {
fromAndroidPlugin
.receiveBroadcastStream()
.listen(_onFromAndroidEvent, onError: _onFromAndroidError);
} void _onFromAndroidEvent(Object event) {
print("文件修改保存路径:" + event);
} void _onFromAndroidError(Object error) {
print(error);
}
...

flutter实践 - plsy的更多相关文章

  1. 干货 | 京东技术中台的Flutter实践之路

    在 2019 年,Flutter 推出了多个正式版本,支持的终端越来越多,使用的项目也越来越多.Flutter 正在经历从小范围尝鲜到大面积应用的过程,越来越多的研发团队加入到 Flutter 的学习 ...

  2. Flutter实战:手把手教你写Flutter Plugin

    前言 如果你对移动端有所关注,那么你一定会听说过Flutter.得益于Google,Flutter一经推出便得受到了广泛关注.很多开发者跃跃欲试,国内部分大厂,诸如美团.闲鱼等团队已经开始了Flutt ...

  3. Flutter混合栈的管理

    Flutter出现的目的旨在统一Android/IOS两端编程,因此完全基于Flutter开发的App,只需提供一个包含FlutterView的页面,后续页面增加/删除/跳转均在FlutterView ...

  4. Flutter 中文文档网站 flutter.cn 正式发布!

    在通常的对 Flutter 介绍中,最耳熟能详的是下面四个特点: 精美 (Beautiful):充分的赋予和发挥设计师的创造力和想象力,让你真正掌控屏幕上的每一个像素. ** 极速 (Fast)**: ...

  5. 微信公众号【阿里技术(ali_tech)】历史文章整理

    简介 来自微信公众号: ali_tech 阿里巴巴官方技术号,关于阿里的技术创新均呈现于此. 本内容来自微信公众号的分享,最后更新时间2019-10-26,请关注对应公众号接收最新分享,定期同步地址: ...

  6. Flutter 实现原理及在马蜂窝的跨平台开发实践

    一直以来,跨平台开发都是困扰移动客户端开发的难题. 在马蜂窝旅游 App 很多业务场景里,我们尝试过一些主流的跨平台开发解决方案, 比如 WebView 和 React Native,来提升开发效率和 ...

  7. Flutter的原理及美团的实践

    导读 Flutter是Google开发的一套全新的跨平台.开源UI框架,支持iOS.Android系统开发,并且是未来新操作系统Fuchsia的默认开发套件.自从2017年5月发布第一个版本以来,目前 ...

  8. Flutter混合工程改造实践

    背景 6月下旬,我们首次尝试用Flutter开发AI拍app.开发的调研准备阶段没有参考业界实践,导致我们踩到一些填不上的坑.在这些坑中,最让我感到棘手的是Flutter和原生页面混合栈管理的问题. ...

  9. Flutter 开发入门实践

    前言: Flutter 是 Google 推出的跨平台解决方案, 开发语言:Dart 优势: 劣势: 学习推荐: 官方网站:https://flutter.io/ 书籍:<Flutter技术入门 ...

随机推荐

  1. python3.6内置模块——random详解

    python内置模块random是用来生成随机数的,在许多场合都能应用到,算是比较常见的一种模块吧,下面详细介绍其具体用法. 基本用法 随机生成浮点数:有两种,一种没有参数,默认是0~1,另一种可以指 ...

  2. MySql数据库,查询数据导出时会出现重复的记录(数据越多越明显)

    在查询数据时,数据量多的时候,我们会使用分页功能. 每页显示多少数据. 这种情况下,一半看不出什么问题. 而导出数据时,有时就是通过分页的方法,逐步讲数据追加到导出文件中. 当全部数据都导出之后,就有 ...

  3. Faraday Future,FF2019年一季度前完成第一阶段5亿美元左右的A+轮融资,2019年年底前完成7亿美元的Pre-IPO轮融资,2020IPO

    FF2019年一季度前完成第一阶段5亿美元左右的A+轮融资,2019年年底前完成7亿美元的Pre-IPO轮融资,2020IPO 区块链公司先行宣布将对FF进行投资.EVAIO(中文名:伊娃)公司 跨链 ...

  4. Python笔记_第二篇_面向过程_第二部分_1.函数

    函数:这个词属于一个数学概念,在编程语言借鉴了这个概念,表现形式是一段程序代码的组合,也叫“程序集”.有过编程基础的人很容易理解这个概念,当我们编写程序越来越多的时候,程序设计大师们会把散乱的程序进行 ...

  5. docker安装文档

    Docker离线安装以及本地yum源构建http://blog.csdn.net/joniers/article/details/64122820http://blog.csdn.net/wsscy2 ...

  6. 放贷额度相关的ROI计算

    违约模型得到概率估计, 将概率值划分5档, 每一档确定一个授信系数 新的授信 = 每月收入* 授信系数 - 老的授信 计算新增授信额度 计算余额损失

  7. 893C. Rumor#谣言传播(赋权无向图&搜索)

    题目出处:http://codeforces.com/problemset/problem/893/C 题目大意:一个城中有一些关系圈,圈内会传播谣言,求使每个人都知道谣言的最小花费 #include ...

  8. C实现日志等级控制

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h&g ...

  9. JAVA并发思维导图

    原博客:https://blog.csdn.net/oqkdws/article/details/82145389

  10. 43)PHP,mysql_fetch_row 和mysql_fetch_assoc和mysql_fetch_array

    mysql_fetch_row   提取的结果是没有查询中的字段名了(也就是没有键id,GoodsName,只有值),如下图: mysql_fetch_assoc 提取的结果有键值,如下图: mysq ...