开发集成环境
[✓] Flutter (Channel stable, v1.12.13+hotfix.9, on Mac OS X 10.14.6 18G103, locale zh-Hans-CN)
一、简述Flutter集成到Android原生项目
二、Android原生以AAR形式集成Flutter项目
三、Flutter与原生(Android/IOS)的消息通信
四、Flutter中如何使用原生控件/组件
五、Flutter状态管理Provider与Redux
六、Flutter升级及开发中遇到的问题汇总
为了解决在Flutter上复用原生视图的问题,Flutter提供了平台视图(Platform View)。通过平台视图,我们可以将原生控件包装成Flutter控件,从而加入到Flutter的渲染树中,获得与Flutter控件一致的用户体验。
方法通道(MethodChannel)
解决的是Flutter与原生系统之间的逻辑通信问题,平台视图(PlatformView)
解决的是Flutter与原生系统之间的视图复用问题。
一、完整的平台视图调用的流程:
平台视图的使用过程和方法通道使用过程大致相似,流程如下:
- Flutter通过向原生视图的Flutter封装类(Android上是AndroidView、iOS上是UIKitView)传入视图标志符,用于发起创建原生视图的请求;
- 原生系统接收到请求,创建原生视图,交给平台视图工厂类(PlatformViewFactory)实现;
- 原生系统将视图标识符和平台视图工厂类进行关联,让Flutter发起的原生视图创建请求可以直接找到对应的视图创建工厂。
二、如何在Android项目中注册原生组件
大致逻辑流程如下:
- 实现原生组件PlatformView提供原生view
- 创建PlatformViewFactory用于生成PlatformView
- 创建FlutterPlugin用于注册原生组件
- 在容器页注册FlutterPlugin
- Flutter中开始使用原生View,展示及修改对应属性。
具体实现步骤如下:
1、实现原生组件PlatformView提供原生view
package com.liujc.testapplication.flutter.androidview;
import android.content.Context;
import android.support.annotation.NonNull;
import android.view.View;
import android.widget.TextView;
import java.util.Map;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.platform.PlatformView;
import static com.liujc.testapplication.util.CCViewPlugin.NATIVE_CCTV_VIEW_TYPE_ID;
/**
* @author liujc
* @date 2020/3/28
* @Description 此处封装原生的TextView给Flutter使用
*/
public class CCTextView implements PlatformView, MethodChannel.MethodCallHandler {
private final TextView myNativeView;
CCTextView(Context context, BinaryMessenger messenger, int id, Map<String, Object> params) {
TextView myNativeView = new TextView(context);
myNativeView.setText("我是来自Android的原生TextView");
this.myNativeView = myNativeView;
if (params.containsKey("myContent")) {
String myContent = (String) params.get("myContent");
myNativeView.setText(myContent);
}
MethodChannel methodChannel = new MethodChannel(messenger, NATIVE_CCTV_VIEW_TYPE_ID+"_" + id);
methodChannel.setMethodCallHandler(this);
}
@Override
public View getView() {
return myNativeView;
}
@Override
public void dispose() {
}
@Override
public void onMethodCall(@NonNull MethodCall methodCall, @NonNull MethodChannel.Result result) {
System.out.println("CCTextView MethodChannel call.method:"+methodCall.method+ " call arguments:"+methodCall.arguments);
if ("setText".equals(methodCall.method)) {
String text = (String) methodCall.arguments;
myNativeView.setText(text);
result.success("修改成功");
}
}
}
2、 创建PlatformViewFactory用于生成PlatformView
package com.liujc.testapplication.flutter.androidview;
import android.content.Context;
import java.util.Map;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.StandardMessageCodec;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory;
/**
* @author liujc
* @date 2020/3/28
* @Description 用于生成PlatformView
*/
public class CCViewFactory extends PlatformViewFactory {
/**
* @param messenger the codec used to decode the args parameter of {@link #create}.
*/
private final BinaryMessenger messenger;
public CCViewFactory(BinaryMessenger messenger) {
super(StandardMessageCodec.INSTANCE);
this.messenger = messenger;
}
@Override
public PlatformView create(Context context, int viewId, Object args) {
Map<String, Object> params = (Map<String, Object>) args;
return new CCTextView(context, messenger, viewId, params);
}
}
3、创建FlutterPlugin用于注册原生组件
package com.liujc.testapplication.flutter.androidview;
import com.liujc.testapplication.util.AhsNativePlugin;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.plugins.shim.ShimPluginRegistry;
import io.flutter.plugin.common.PluginRegistry;
/**
* @author liujc
* @date 2020/3/10
* @Description 用户注册原生组件
*/
public class CCViewPlugin{
public static String NATIVE_CCTV_VIEW_TYPE_ID = "com.cc.flutter/cctextview";//原生控件对应的viewtypeid
///
/// @Params:
/// @Desc: 兼容1.12以前旧版本
///
public static void registerWith(PluginRegistry registry) {
final String key = AhsNativePlugin.class.getCanonicalName();
if (registry.hasPlugin(key)){
return;
}
PluginRegistry.Registrar registrar = registry.registrarFor(key);
registrar.platformViewRegistry().registerViewFactory(NATIVE_CCTV_VIEW_TYPE_ID, new CCViewFactory(registrar.messenger()));
}
///
/// @Params:
/// @Desc: 新版本注册方式
///
public static void registerWith(FlutterEngine flutterEngine) {
final String key = CCViewPlugin.class.getCanonicalName();
ShimPluginRegistry shimPluginRegistry = new ShimPluginRegistry(flutterEngine);
if (shimPluginRegistry.hasPlugin(key)){
return;
}
PluginRegistry.Registrar registrar = shimPluginRegistry.registrarFor(key);
registrar.platformViewRegistry().registerViewFactory(NATIVE_CCTV_VIEW_TYPE_ID, new CCViewFactory(registrar.messenger()));
}
}
4、 将封装的原生View注册给Flutter使用
public class MainActivity extends FlutterActivity {
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
CCViewPlugin.registerWith(flutterEngine);
}
}
5、在Flutter中使用CCTextView
Container(
width: deviceUtil.setWidth(200),
height: deviceUtil.setHeight(100),
child: AndroidView(viewType: "com.cc.flutter/cctextview",
creationParams: {
"myContent": "我是flutter通过参数传入的文本内容",
},
creationParamsCodec: const StandardMessageCodec(),
onPlatformViewCreated: onCCViewCreated, //初始化
),
)
//具体根据平台判断 defaultTargetPlatform == TargetPlatform.android
初始化MethodChannel信息,用来更新CCTextView的属性值
MethodChannel _channel;
void onCCViewCreated(int id) {
_channel = new MethodChannel('com.aihuishou.business/cctextview_$id');
setMyViewText("默认值");
}
//调用setCCViewText可执行setText方法,对应上面CCTextView的onMethodCall对应接收操作
Future<void> setCCViewText(String text) async {
assert(text != null);
return _channel.invokeMethod('setText', text);
}
网友评论