Flutter集成页面效果图

集成

Gradle升级
1、buildTools gradle升级到3.0.1
加快编译速度,已经编译过的无需重新再编译,编译总时间,是以前的一半;
2、Gradle 环境升级到4.1
Flutter依赖gradle环境3.0.1以上;
3、升级gradle后lib模块中没有monkey,debugProguard
buildType时,兼容使用debug
//如:
debugProguard {
matchingFallbacks = ['debug']
}
4、git升级到2.0以上
如果不升级,执行flutter packages get会报如下错误:
The current Flutter SDK version is 0.0.0-unknown.
Because flutter requires Flutter SDK version >=0.1.4 <2.0.0, version solving failed.
Flutter SDK version.dart会判断git版本,升级git到2.0问题解决;
Flutter页面及混合栈管理
引入Flutter之后,我们首要面临的问题便是混合栈的管理。如我们首先实践的是向导页,则有一个常见的应用场景:产品详情页->向导页->向导详情页-->分享界面(右上角底部弹层)。如何去解决这种Native 与Flutter任意嵌套的问题呢?
1、每个页面有个Activity,保证页面逻辑正常工作;
2、Flutter和Native页面直接正常通讯,共享数据;
3、Native页面可任意呼起Flutter页面,Flutter页面可正常呼起Native页面
4、用户体验无差异
为了解决这些问题,设计如下:
1、所有的Flutter页面复用一个FlutterActivity;

restoreBundle 负责路由参数解析
TNFlutterEvent 负责Bridege通讯
mComponentName Flutter页面名称
mComponentParams 页面参数
base里公用Natvie中打点及设置等;
2、每个Flutter页面都有一个Activity,通过mComponentName区分不同页面,通过参数传递进入到对应的的flutterPage;
3、Flutter Page调用Bridge通过OpenUrl路由解析,任意呼起页面;
4、所有的页面跳转和动画都通过Native实现
因为原生(iOS/Android)自带跳转动画,而Flutter内部跳转也自带动画,为了用户体验,Flutter内部跳转(push/pop)相关动画,统一由Native接管,这样用户就感受不到差异。
5、混合栈管理流程图

通讯方式:
1.Flutter调用Native
Flutter端:
static dynamic setOpenUrl(url) async {
if (url == null) {
return null;
}
Map<String, String> map = new Map();
map['url'] = url;
try {
var result = await platform.invokeMethod('resolveUrl', map);
return result;
} on PlatformException catch (e) {
print("---->" + e.message);
}
return null;
}
Native端
@Override
public void onMethodCall(MethodCall call, Result result) {
//onMain Thread
LogUtils.i(TAG, "call native method {}:--arguments-----{}---->", call.method, call.arguments);
// 在这个回调里处理从Flutter来的调用
testSuccessful = call.method.equals("success");
testFinished.open();
invokeMethod(call, result);
}
private void invokeMethod(MethodCall call, Result result) {
try {
Method method = FlutterBridge.class.getMethod(call.method, Activity.class, Object.class, Result.class);
method.invoke(null, mActivity, call.arguments, result);
} catch (IllegalAccessException e) {
FlutterBridgeUtil.invokeErrorCallback(result, RNConstant.ErrorCode.NOT_FOUND);
} catch (InvocationTargetException e) {
FlutterBridgeUtil.invokeErrorCallback(result, RNConstant.ErrorCode.NOT_FOUND);
} catch (NoSuchMethodException e) {
FlutterBridgeUtil.invokeErrorCallback(result, RNConstant.ErrorCode.NOT_FOUND);
}
}
2.Native调用Flutter
Flutter端
static const EventChannel _eventChannel =
const EventChannel('com.tuniu.app.ui/stream');
void listenNativeEvent() {
_eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
}
void _onEvent(Object event) {
//print("Battery status: ${event == 'charging' ? '' : 'dis'}charging.");
print('---_onEvent---11->' + jsonEncode(event));
String str = jsonEncode(event);
setState(() {
_batteryLevel = 'level at $str';
});
}
void _onError(Object error) {
print('---_onError---11->' + 'Battery status: unknown.');
String str = jsonEncode(error);
setState(() {
_batteryLevel = 'level at 1 $str';
});
}
@override
void initState() {
super.initState();
listenNativeEvent();
}
Native端
public TNFlutterEvent(FlutterView flutterView) {
//添加广播通知
final EventChannel eventChannel = new EventChannel(flutterView, TNFlutterMethodCall.STREAM);
eventChannel.setStreamHandler(this);
EventBus.getDefault().register(this);
}
/**
* 监听登录结果
*/
public void onEvent(LoginEvent loginEvent) {
if (loginEvent != null) {
LogUtils.i(TAG, "send event: {}, params: {}", RNConstant.RNEventConstant.EVENT_NAME_LOGIN_STATUS_CHANGED, JsonUtils.encode(loginEvent));
// 把状态发给Flutter
if (mEvents != null) {
mEvents.success(JsonUtils.encode(loginEvent));
}
}
}
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
LogUtils.i(TAG, "onListen------>");
if (eventSink != null) {
this.mEvents = eventSink;
}
}
@Override
public void onCancel(Object o) {
}
/**
* 接收eventbus 事件
*
* @param notify 参数供回调
*/
public void onEvent(NotificationRequest notify) {
// 把状态发给Flutter
if (mEvents != null) {
mEvents.success(notify);
}
}
public void onDestory() {
EventBus.getDefault().unregister(this);
mEvents = null;
}
图片加载
1、图片缓存
无法和Native公用一套缓存图片框架,采用
cached_network_image 框架
2、支持webp,gif等图片格式,支持本地图片
内存,CPU占用
Flutter向导页面

RN向导页面

Flutter,RN性能对比
测试环境,华为荣耀6,系统版本:6.0

FPS流畅度,暂未采集,从肉眼观察,比RN流畅
布局

向导页整体结构
主题风格,滑动,吸顶,tab切换,上拉加载,下拉刷新
网友评论