前语
参考资料
将Flutter增加到现有Android项目-官网
撰写双端渠道代码(插件编写完成)
Flutter 混合栈复用原理
Flutter发动页(闪屏页)详细完成和原理剖析
Andr? Poid混合开发跳e , ( K转Flutter黑屏问题解决办法
目录
一、创立Flutter Module并进行相关装备
Android项目中创立Fluf 3 ( N & Mtter Module 与其通讯交互
1、创立Flutter ModE m yule,笔者将所创立的flutter_t { j a pmodule放在e 1 j # ;跟AS创立的APP项目同一目录层级上。
flutter crp 0 c w : = # ;eate -t module flutd m 7 C m pter_module
/, Y c c/或者
// Android Studio new Flutter Project -> flutter module
2、装备 官网装备
1.android项目的settings.gradle,不用导包
setBinding(new Binding([gradle: this]] } V))
evaluate(new File(settingsDir4 d f B J t % [.parentFile, 'flutter_module/.android/include_flutter.groovy'))
2.同步后,再在android项目的app模块中即可
implemenY | , W y p Ptation project(':flutter')
3、V * u _ – ^ $ KJava中调用Flutter 进入Flutter相} ` h } – 3 y – c关页面
官网介绍 Flutte4 | = ^ Mr增加到现有Android项目 里边有关于怎么增加FlutterActivity和FlutterFragment的
留意一些FlutterActivity需求注册到清单文件里
例如以下从native app 跳转到Flutter的主页面,并传递数据给Flutter,记住FlutterFragment的生命周期,按照官网写即可
public void goToFlutterClick(View) ( w o z U view) {
startActiv5 P v & l city(FlutterActivity.with* t J ^ 4 %NewEngine().initialRoute("Flutter Activity").build(this));
}
public void goToFlutterTarH N nget(View view) {
FlutterFragment flutterFragment = FlutterFragment.withNewEngine().initialRoute("Flutter Fragr ! 1 % Vment").build();
getSupportFragmentMai F z T Y 0 w h Gnager().beginTransaction().add(R.id.container, flutterFragment, "TAG").comm ^ k ^ biti a @ s();
}
}
当$ 9 W你试往后,会发现两个问题
-
Native APP跳转Flutter呈现先黑屏再显现问题 , 解决方案能够检查 Android混合开发跳转Flutter黑屏问题解决办法} & C Flutter发动页(闪屏页)详细完成和原理剖析 个人解决办法是在原生Activ T @ Gvity里边增加一个FlutterFragment就好了,没有呈现黑屏,能够看接下来的示例代码
-
这样写,每次都重启了新的一摸相同的D ( Q ?Flutter APP,解决办法Y q E ^ O便是经过再main.dart中,依据传递的参数来指定要显现的路由名,以确定& H N ) ` 6 2要创立哪个窗口小部件给runApp
void main() => run(_widgetForRoute(window.defaulF ` n tRouteName)) W( ? G 9 r ( : ] 9idget _widgetForRoute(String route){ switch(route){ case 'route1': return Widget1(); case 'route2': return Widget2(); dv L E +efault: return Center(child:Text('Are You Ok ?')); } }
小技巧:履行flutter attach指令后,在4 F i Iflutter端更改的代_ Q F码也能够运用热加载、热重启功能。调试的时分,在Androd Studio上找到Flutter Attach按钮,点击,然后发动APP即可。
二、Flutter与Native通讯示例
Flutter中定义了三种不同类型的Channel
-
BasicMessageChannel : 用于传递字符串Q Z | 和半结构的信息,持续通讯,收到音讯后能u z ; ? T够回复此音讯。如Native将遍历到的文件信息连续传递到Da: j 2 + #rt,Flutter将从服务端连续获取的信息给Native。
Flutter与原生项目的资源是不同享的,能够经过BasicMessageChannel来获取Native项目的图标等资源
-
MeS h .thodChd A Nannel : 用于传递办法调用, 一次性通讯 ,比方Flutter调用Native获取体系电量,建议Toast调用。
-
Evente M U 4 % , ?Channel : 用于数据流(event streams)的通讯,持续_ J z ( W d )通讯,收到音讯后无法回复此次音讯,通常用于Native向Dart的通讯,如:手机电量改变、网络连接改L 2 J y 6 X变、传感器等。
1、BasicMessageChannel
简略作用
代码
Native端
//1
import io.flutter.embeddJ R 8 @ b f K 2ing.android.FlutterFragment;
// import xxxxxxx
public class FlutterTestActiZ K } r 8 qvity extend W * -s AppCompatActivity implements IShowMessage, View.On9 K 6 y / -ClickListener {
private EditText mInput;
private Button mSend;
privQ a d ate BasicMessageChannelPlugin basicMessageChann| u U Z ? - W U {elPlugin;
private FlutI i l f $ P xterFragment mFlutterfragment;
private EventChannelPlugin eventChannelPlugin;
@Override
protected void onCr+ n _ n s @ Aeate(@Nullable Bundle sa? T vedInstanceState) {
super.onCreate(savedIn$ # F O , ; ^ +stanceState);
setContentView(R.layout.test);
mInput = findViewById(R.iM 0 yd.input);
mSend = findViewById(R.id.send);
mFlutterfragment = FlutterFrao ( e Y a Z { gment.withNewEngine().initialRoute("Flutter Fragment").build();
getSupportFragmentManager().beginTransac, a 6 htion().add(R.id.flutter_test_fragment, mFlutterfragment, z l E"TAG").commit();
}
public void basicChannelClick(View view){ 5 @ : - + A x y {
basicMessageChannelPlugin = BasicMessageChannelPlugin.reS ) ~ l Y b rgisterWith(this,mFlutterfragment.getFlutterEngine().getDartExecutor().getBinaryMessenger());
}
public void methodChannelClick(View view) {
MethodChannelPlugin.regisv X _ eterWith(this,mFlutterfragmen3 z } Q 1 k Bt.getFlX x w S f R ` z WutterEngine().getDartExecutor().getBinaryMessenger());
}
public void eventChannelClick(ViewL Z * F 1 view) {
eventChannelq 4 H 3Plugin = EventChannelPlugin.r% Z ~ * j YegisterWith(mFlutterfragment.getFlutterEngine().getDartExecutor().getBinaryMessenger());
}
@Override
public void onShowMessage(String message) {
Toast.makeText(this, "I hava receive " + message, Toast.LENGTH_SHORT).show();
}
@Override
public void onClick(View view) {
if(view =6 n | ? v : @ X= mSend){
if(!TextUtils.isEmpty(mInput.getText().toString().trim())){
basicMessageChannelPlugin.send(mInput.getText().toString().trim());
// eventChannelPlZ 7 yugin.send(T y f | ? w hmInput.getText().toStri~ = 0ng().T N I r 3 Strim());
}
}
}
}
/1 s { W/2
/**封装收发音讯*/@ % K d @ x ?
public class BasicMessageChannelPlugin implements BasicMessageChannf d O P u i w uel.MessageHandler<String>, BasicMessageChannel.Reply<String> {
private final Activity acti3 2 v n t / N b [vity;
private final BasicMessageChannel<String> messageChannel;
/**b ` F $ 5
* 提供给外部调用注册
*
* @param binaryMessenger
* @return
*/
public static BasicMessageChannelPlugin registerWitm | m K 1 q ih(Activity activity, BinaryMessenger binaryMessenger) {
retu* ) r a p P ` Arn new BasicMessageChannelPlugin(activity, binaryMessenger);
}
private BasicMessageCh0 K + E B L R * ZannelPlugin(Activity activity, BinaryMessenger binaryMessenger) {
this.activity = activity;
// name 作为通道V X B x仅有标识,Dart端也需求相同
this.messageChannel = new BasicMes` 3 f e ` @sageChannel<l c X;> 8 C(binaryMessenger, "BasicMessf A v q X L m uageChannelPlugis H on", StringCodec.INSTANCE);
//设置5 a ` t音讯处理器,处理来自D~ G - a i U Y cart的音C r )讯
messageChannel.setMessageHandler(this);
}
/**
* 接纳到) z h p y r f音讯后的处理
*
* @par. y - k Nam messF 2 T 2 1 K 4 age
* @param reply
*/
@Override
public void onMessage(@Nullableq $ E M r ^ B 6 $ String message, @NonNull BasicMessageChann( Y , zel.Reply<String> reply) {
Log.i("Basic", "收到Dart Send -> " + message);
//经过replay回复Dart
reply.reply("Native回复 -> BasicMessageChannel 收到 " + message);
if (activity instanceof IShowMessage) {
//IShowMessage为Activity完成的接口,这儿首要用来处理收到的G J @ 3 + } M音讯
((IShB { T 2 r P F Y xowMessage) activity).onShowMessage(message);
}
Toast.makeText(activity, messagee ) @ j ` y +, Toasti | p.LENGTH_SHORT).show();
}
/**
* 发送音讯
*
* @param message 发送的音讯内容
* @paramC F G $ g ! j * callback 发送音讯后,Dart端的反应
*/
vo$ T N B X ! U P 6id send(String message, BasicMessageChannel.Reply<String> callback) {
messageChannel.send(message, callback);
}
public void send(String message) {
send(message, this::reply);
}
@Override! [ o
public void reply(@Nullable String reply) {
//用于Send中接纳Dart的反应
if (activity instanceof IShowMessa9 E ; D R ~ G ; ~ge) {
//IShowMeC ? ^ssage为Activity完成的接口,这儿首要用来处理收到的音讯
((IShowMessage) a; v D p z ~ T ^ Uctivity).onShowMessage(reply);
}
}
}
//3
test.xml
<?xml version="1.0" encob 5 M b %ding="utf-8"?>
<LinearLayout xmlns:android="http://schem- ) c k u 9as.android.co` ! q sm/apk/res@ ~ w 9 a I % A 5/android"
android:layo2 M w # C fut_width="m& 4 P gatch_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="basicChannelClick"
android:text="BasicMessageChannel"
android:tek f Z g ` ! _ h /xtAllCaps="false" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="methodChannelClick1 A N X c"
android- a P Z v w:tK ; : #ext="MethodC( j m c r _hannel"
android:textAllCaps="false" />
<Button
android:layout_width="match_paV 1 k e F f mrent"
android:layout_height="wrap_content"
android:onClick="eventChannelClick"
android:text="EventChannel"
android:te` + * UxtAllCaps="false" />
<LinearLayout
android:layout_width="matcC = X D h r qh_parent"
android:layout_height="wrap_content"
andr6 ` O ]oid:orientaO V 1 U }tion="horizontal">
<EditText
android:id="@+id/1 4 [ ^ V 1input"
android:layout_width="0dp"
android:layh d ^ =out_height="wrap_content"
android:layout_weight="1" />
<Button
android:id="@+id/send"
android:layoua e P n Nt_width="wrap_conte! F 4 ~ h ~nt"
android:layout_height="wrap_content"
android:text="发送" />
</LinearLayout>
<TextView
android:id="@+id/show"
android:layout_width="match_parent"
android:layout_height=~ & H & +"wrap_content" />
<FrameLd ! ? 0 B / E kayout
android:id="@+id/flutter_test_fragmen^ R S ! ] Et"
android:layout_widt- i t U K f X { )h="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Dart端
//修改创立的默许文件
class _MyHomePageState extends State<MyHomePage> {
static const BasicMessageChannel _basicMe- X | A p l u I gssageChannel = const BasicMessageChannel("BasicMessageChannelPlugin", StringCodes ? i o N #c());
String receiveMessage = "";
@override
void initState() {
// TODO: implement initState
super.initStatq l F {e();
_basicMessageChan( S x * 1 5 u Hnel.setMessageHandler((message) => Future<String>((){
setState(() {
receiveMessage = message;
});
//收到音讯后通知Native端
return "收到Native 的音讯 : "+2 2 m G | message;
}));
//向Native发送音讯不等候回复
_basicMessageChannel.send("Flutter Init Ok !");
}
//向Native发送音讯并接纳回复
_send(messH } [ - Q ; |age) async{
String response = await _basicMessageChannel.send(message);
print('nativB r K l . [ T + ;e reply '+ response);
}
@override
Widget build(BuildContext context) {, d B y S
retS s V F # , E durn ScaffS u 6 j k L b Hold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxp z n x - d $isAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushK % 0 A M h 4 : )ed the button this many times:',
),
Text(
'$receiveMessageD j ; d M 7',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
//onPressed: _sendToDart,z s m ` Z { n
child:, F U Icon(Icons.add),
),
);
}
}
2g : c : ! ,、MethodChannel
官网MethodChan# 4 ] A @ / p 6 Znel获取电量示例
简略作用
代码
Native端
Activity代码上面剖析BasicMessageChannel已经贴出来的,注册一下即可
public class MethodChannelPlugin implements MethodChannel.MethodCallHandler {
prb m d 0ivate final Activity activity;
public static void registerWithx j ; ? ) ` Z(Activ) F f ) + + ) v Eity activity, BinaY D $ H W z EryMessenger binaryMessenger) {
MethodChannel channelw Q p j V = new Met3 ^ ; Q ! xhodChannelP k g | E L e =(binaryMessenger, "MethodChannelPlugin");
MethodChannelPlugin instance = new Method_ r I D z K kChannelPlugin(activity);
channel.sek | _ s 2tMethodCallHandler(instance);
}
private MethodChannelPlugin(Activity activity) {
this.activity = activiS { $ cty;
}
@Override
publi| . $ Tc void onMethodCall(@NonNull MethodCall call, @U K # Q ;NonNull Meth2 , 8 i { 4 8 % GodChannel.Result rC [ Jesult) {
//处理来自Dart的办法调用
switch (call.method)8 G a } | + 3 Q ; {
case "show":
Log.i("MethodChannel","show办法 "+call.argumen3 K P D r & I } Ots());
showMessage(call.arguments());
//将回来结果给Da[ A g ert
result.success("MethodChannelPlugin收到 " + call.arguments} K { ~ Q x o);
break;
default:
result.notImplemented(e A _ M q);
break;
}
}
private void showMessage(String a1 | A c 0rguments) {
if (activity| S o m + u instanceof IShowMessage) {
((IShowMem I | 4 K a u Yssage) activity).onShowMess& , 2 x q P n [ Tage(arguments);
}
}
}
Dart端
以下代码增加到p 7 ( S上面剖析BasicChannel的_MyHomePa[ ` ,geState 即可,相似相同写
static co/ _ ynst MethodChannel _methodChannel = MG * m % ðodCha. b f , a H @ Gnnel("MethodChannelPlugin");
floatingActionButton: FloatingActionButton(
onPressed: _sendToD% M iart,
child: Icon(Iconp Z U V 2 q ( Ls.add),
),
_sendToDart() {
_methodChannd r P E . 6el?.invokeMethod("sho) U x Rw", 'Dart问好')?.then((valu6 ( Ce) {
setState(() {
th= W a # x L ? _ fis.receiveMessage = value;
});
})?.catchError((e) {
print(e);
});
}
3、EventChannel
简略作用
代码
Native端
public class EventChannelPlugin implements Eventh 8 E (Channel.StreamHandler {
private EventChan| 2 S [ 0 {nel.EventSink eventSink ;
public static EventChannelP{ 9 ; } i Llugin registerWith(BinaryMessenger binaryMessenger) {
EventChannelPlugin plugin = new EventChannelPlugin();
new EventChannel(binaryMessenger, "EventChannelPlugF L yin").setStreamHandler(plu] a s a ^ Hgin);
return plugin;
}
public void send(Object params){
if(ev! 5 ,entSink == null){
return;
}
eventv - , H B J 4 a DSink.success(params);
}
/**
* Native监听事情时回调
* @param arguments0 A E a f , 传递的参数
* @param events Native回调Dart时的回调函数
*/
@Override
public void onListen(Object argumek 9 y o hnts, EventChannel.; O I & @ ] z !EventSink events) {
Log.i("EventChannW b o c S @ g B wel","onListen " +arguments);
this.eventSink = evex @ S e : 1 b $ pnts;
}
/**
* Flutter撤销监听: o P D : f w T _时的回调
* @param arguments
*/
@Override
public void onCancel(Object arguments)A d 6 d {
eventSink = null;
}
}
Dart端
以下代码增加到上面剖析Bak / 5 k 3 DsicChannel的_MyHomePageState 即可,相似相同写,记住注册e C - C z ]的事情在页面毁掉` [ l u V E P时需求撤销监听
sw l e gtatic const Even: B 9 7 X k ( :tChannel _eventChannel = EventChannel("EventCha5 J + S i Ynnel* b V O 5 y #Plugin");
floatingActionButton: FloatingActionButton(
onPressed: _sendToDar0 / Wt,
child: Icon(Icons.add),
),
_sendToDart() {
_streamSubscription = _eventChannel
.receiveBroadc0 h & ~ 5 _astStream("123")
.liste # W D e Y D fn(_onToDart, onError: _onToDartError);
}
_onToDa) T R ; i -rt(message) {
setState(() {
this.receiveMessage4 H I + = R g J = "EventChannel " + message;
});
}
_onToDartError(error) {
print(er9 F m w : Wror);
}
@oveq @ q $ / e 9rride
void dispose() {
super.dispose();
if (_stred 5 + U z L IamSubscriptik n U Y L * = fon != null) {
_stream% x U ` Q jSubscription.cancel();
_streamSubscription = null;
}
}
三、Flutter与NativeG F H 7 P通讯源码剖析
几个Channel办法的运用都很简略,这儿首要介绍一下MethodChannel
在之前剖析的MethodChannel中,能够看} F ;出,只需两端注册同一个name的Channel就能够让Flutter端经过invokeMethod调用,回来一个Future目标,用于接纳Native端回来的信息,Naq P l D D 6ti6 V [ $ g e ) lve层是经过onMethodCall中J R Y T K 8 C p z的Result类来处理相关事情的Z : } l A u B。
1、咱y X N J们先@ K – ^剖析Native端 MethodChannel,首要是MethodChannel的结构函数和设置音讯处理的setMethok q +CallHandler办法
1.结构函数
public MethodChannel(BinaryMessen= P G 8 R 2 tger messengerX f _ # P = 6, String name) {
this(messenger, name, StR H | w K ( I ; andardMethodCodec.INSTANCE);
}
public MethodChannel(BinaryMessenger m2 g 7essenge% s { L & A _ dr, String name, Meb W 3 | H % %thodCodec codec) {
if (BuildConfig.DEBUG) {
if (messenger == null)N , 8 {
Log.e(TAG, "p o W LParameter messenger must not be null.");
}
if (name == null) {
Log.e(TAG, "Parameter name must not be null.");
}
if (codec == null) {
Log.e(TA4 8 l E 7 T U a eG, "Parameter codec must not be null.");
}
}$ , E p - N S
this.messenger = messenger;
this.name = name;
this.codec = codec;
}
2.setMethodCall` G x t wHandler 中 会将name和handler| k D ]传递给m8 5 E Aessenger
@UiThre? g X t had
public void setMethodCallHandler(final @Nullable MethodCallHandler handler) {
messenger.setMeD n s L a k %ssaB T ^ 5 i g $geHandler(
nu v g v A b I k xame, handler ` p 5 == null ? null : new Inw i T 3 P f 3comingMethodCallHandler(handler));
}
从上面的setMethodCallHA 0 , ^ g Z *andler能够看出关键点在于messenger和InW : = l c 9 D XcomingMethodCallHandler
messenger
这儿的messenger其实n , ^ , ( Q便是BinaryMessenger,FlutterView和DartExecutor 等都完成了该接口,好多地方都运用FlutterView,因为这儿Flutter版本是1.7的,不能经过老版本FlutterVz C y e v V 7 }iew去创立一个FlutterFragment,除非你Activity集成FlutterActivity,默许的getFlutterVieN i V F Sw()办法会回来FlutterView。应该是这样的。
代码中经过mFlutterfragment.getFlutterEngine().getDarV S # V 5 M * xtExecutor().getBinaryMessenger` Y a W & . p ; 4()得到BinaryMessenger,所以setMethodCallHandler调用的是这个BinaryMessenger的setMethodCallHandler办法,而这个Binary[ 6 O & B W B 1 cMessenQ P S 5ger其实便是DartExceutor的dartMessenger目标
持续盯梢DartExecuto: U z M ] c ]r的dartMessenger目标
public DartExecutor(@NonNull FlutterJNI flutterJNI, @NonNull AssetManager asw [ G y k a GsetManager) {
this.flutterJt 2 # B NI = flutterJNI;
this.assetManager = assetManager;
tB X % G R k L D -his.dartMessen} & P Y Xg& 6 ` V 4 4 S P zer = new DartMessenger(flutterJNI);
dartMessenger.setMessageHandler("flutter/isolate" W # ? f R N Q L, isolateChannelMessageHandl` i t 5 & Ter);
this.binaryMessenger = new DefaultBinaryMessenger(dartMessenger);
}
能够看到dartMessenger是在这儿初始化的,这Q 0 6个结构函数的履行在FlutterEngine里和FlutterNU m f m Z yativeView里,至于哪个办法里履行,以后再剖析,能够理解为在发动FlutterFragment的时分会履G # ] 7 C e行。
所2 ^ V * V ) = ,以咱P J # @们只需求看DartMessenger的setMessageHandler办法
@Override
public void setMessageH j _ a randler_ ( H ? L _ @ 7 &(
@NonNull String channel, @Nulld S Qable BinaryMessenger.BinaryMessageHandler handler) {
if (handler = ~ M k t= null) {
Log.v(TAG, "RemB U 3oving handler for channeL Y } D = w ? hl '" + channel + "'");
messageHandlers.re! _ ? Y { Emove(channelK T v g W | G e);
} else {
Log.v(TAG, "Setting handler fc G ~ [or channel '" + channel + "'");
messageHandlers.pu8 N ( } I n ! zt(channel, handler);
}
}
从上述代码能够看出, 将name作为key,IncomingMetho~ X r C . b X ( 3dCallHandler作为value,存放到了HasZ k 7 n I Z FhMap类型的messageHandlers中,经过key! k ( W 7 k # %就能够0 1 m X m : `找出对应的Handerl,然后履行相关办法(onMessage办法)。
IncomingMethodCallHandler
private fis ? 2 c M w 8nal class IncomingMethodCallHandler implemeB @nts BinaryMessageHandler {
private final MethodCallHandler handler;
IncomingMethodCallHandler(MethodCallHandler handler) {
this.handler = handler;
}
@Override
@UiThread
public void onMessage(ByteBuffer messa _ / a 3ge, final Binary| o ! _ r + 7 , =Reply reply) {
final MethodCall call = codec.decodeMetu p !hodCall(message);
//.......
}
}
2、咱们再来看看Flutter端
首要代码如下
static const MethodChannel _methodCF J F h ,hannel = MethodChannel("MethodT C D u 3ChannelPlugin");
_methodChannel?.invokeMethoO U n a Wd("show", 'Dart. i q -问好')?.then((value) {
setState(() {
this.receiveMe^ # g ~ lssage = value;
});
})?.catchError((e) {n 3 O 8 @
print(e);
});
MethodChannel结构函数
const MethodChannel(this.n5 o U ] y qame, [L Z C Fthis.codec = const StandardMeX D ; Z - 0 CthodCodec(), BinaryMeI ` | 2 x I K Q 8ssenger binaryMessenger ])
: assert(name != null),
assert(p x c K [ } h pcodec != null),
_binaryMessenger = binaryMessengv 8 l w per;
invokN ? 8 g = f ; reMethod办法
@{ i O v T a |optionalTypeArgs
Future<T> invokeMethod<T>(String method, [ dynamic arguments ]) {
return _iny ) y t ; j )vokeMethod<T>(method2 B g n ~ f, missingOk: false, arguments: arguments);
}
@optionalTypeArgs
Future<T&g0 ! m ~ x &t; _invokeMethod<T>(String method, { bool missingOk, dq d M | S , e gynamic arguments }) async {
assert(method != null);
final ByteData result = awai$ % y , &t binaryMessenger.send(
name,
codec.encoO + ~ ) } l o ^ _deM` N $ u xethodCall(MeX 7 _ & Y _ T vthodCall(` O Imethod, arguments)),
);
if (re+ i l d d bsult == null) {
if (missinD m y U | VgOk) {
return null;
}
throw MissingPlugint v 9 I P Y dException('No implementation found for method $method on channel $name');
}
return codec.decodeEnvelope(result) as T;
}
能够看到_invokeMethod办法内,首要把办法明和参数经过codec转换为二进制数据,经过BinaryMessages send出去。
这儿的binaryMessenger没有设置,所以是默许的defaultBinaryMessenger,盯梢发现是_DefaultBinaryMessenger类型目标,它是继成BinaryMessenger的。持续看它的send办法
//1
@override
Future<ByteData> senJ ~ f ]d(String channel, ByteData message) {
final- K L 2 c t w MessageHandler handF Z } * 5 + ,ler = _mockHandlers[channel];
if (handler != null)
//A
returnt A D 4 V d x a handler(mess$ = t H hage);
//B
re^ | l Hturn _sendPlatformMessage(cha1 0 S T Annel, message);
}
//2
Future<ByteData> _sendPlatformMessage(v : 6 ] pString channel, ByteData message) {
final Completer<ByteData> completer = Completer<ByteData>K V R z % 6 G `;();
ui.window.sendPla8 Y . % U * ztformMessage(channel? c j 3 T O E l 4, message, (ByteData reply) {
//....
});
return completer.future;
}
//3
void sendPlatfo1 ) ~ TrmMessage(String name,
ByteData data,
PlatformMessageResm g jponseCallback callback) {
final String em h B a F arror =
_d ? gsendPlatformMessag c M 8e(name, _zonedPlatfoI * e z QrmMessD d = @ageResponseCallback(callback), data);
if (error != null)
throw Exception(error);
}
//4 window.dart
String _sendPlatformMessage(String name,
PlatformMessO E ` . Z t ] tageResponseCala a , 6 vlback call} g P jback,
ByteDa* G 5 !ta data) native 'Window_sendPlatformMessage';
上面注释A处,
MessageHandler* ! I C t ~>的Map,能够在F! E I Mlutter中 2 &mock住某个channelName,这样的话,发I U I B ^ T ]送这类音讯就会走自己在Flutter写的handler。咱们需求和Native通讯,自然这儿没有mock住。
注释B处,从办法名就能够看出,这儿是和渠道通讯的相关逻辑,首要是调用了ui.window.sendPlatformMessage办 – – o 0法,能够看后边 3 和 4,会发现调用的都是FlutterEngine的库办法,然后会调用dart的native办法 Window_sendPlatformMessage(y V S)。
Flu9 z g o X atter Engine部分逻辑
这块先总a P s结以下,Dart的Native机制会事先注册一个对native办法的映射表,上面那个dart的native办法会经过JNI层找到对应的java native层办法,调用其_ O Q . & a [ F M办法回到java native层,回到java层。
Dart的Native机制是先注册一个对Native的办法映射表
void Wo h b l x D /indow::Reo 3 }gisterNatives(tonic:L [ 5 I:DartLibraryNatives* natives) {
natives->Register({
{"WiO c d 5 * n fndow_defaultRouteName", DefaultRouteNe 2 U V M xame, 1, true},
{"Window_scheduleFrame", ScheduleFrame, 1, truf r n ~ Ye},
{"Window_sendPlatforms _ n = - | L i mMessage", _SendPlatformMes! T i +sa6 - , @ 1 Sge, 4, true},
{"Window_respondToPlatformMessage", _RespondToPlatformMessage, 3, true},
{"Window_render", Render, 2, true},
{"Window_u$ m tpdateSemantics", UpdateSemantics, 2, true},
{"5 T SWindow_setIsol/ k n ` + 8 6ateDebugName", SetIsolateDebS T c Y Y zugName, 2, true},
});
}
咱们能够找到对应的办法是_SendPlatformMessage
,这个办法会调到SendPlatformMessage
Dart_Handle SendPlatformMessage(Da0 h / trt_Handle window,
const std::string& name,
D` + / V 1 9 v L Qart$ 2 ! + t - D r_Handle callback,
const tonic::DartByteData& data) {
// ...
if ($ / j ^ bDart_IsNull(data.dart_handle())) {
dart_ss M 1 V r Ytate->window()->client()->| { , T a 3;HandlePlatformMessage( // A
fml::MakeRefCounted<PlatformMessage>(name, responsz B g n se));
} else {
const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
dart_state->window()->client()->HandlePlatformMessage( /; ! X w % {/ A
fml::% $ ! F ZMakeRefCounted<PlatformMessage>(
name, std::vecto5 1 U Qr<uint8_t>(buf4 y v x + 6 E B ffer, buffer + data.length_in_bytes()),
response));
}
returnU U l G ! * E x [ Dart_Null();
}
能够o V H : L ^看 注释 A 处,最终都是会调到WindowClient的HandlePlatformMessage
办法,WindowClient~ / Z u ) U z = `的详细完成是Runtimx K ; j K Z }eController,然后Runtm $ d ` 8imeControlleg ? D P { ? 4 , ur会将办法交给RuntimeDelegate来完成,而RuntimeDelegate的详细完成则是Engine类,这个类中的办法完成如下
void Engine::HandlePlatformMessage(
fml::RefPtr<blink::PlatformMessage> message) {
if (message->channel() == kAssetChannel) {
HandleAssetPlatformMessage(std::move(message));
} else {
delegate_.OnEngineHandlePlatformMessage(std::move(messagj m g 1 k y 4 G |e));
}% % ` : (
}T o Z I ] 7
检查 HandleF % l I e Z p G TAssetPlatf3 H _ C SormMessagel W 7 6 ~(std::move(message)); 办法
void PlatformViewAndroid::HandlePlatformMessage(
fml::RefPtr<blink::PlatformMessage> message) {
JNIEnv* env = fml::jn! : d 3 b z = xi::AttacO b . ) Z C WhCurrentThreadY P 3 9 -();
fml::j$ d 8 x Jni::ScopedJavaLocalRef<jobject> view = java_object_.get(env);
// ...
auto java_channelq + ^ ; y % H f 8 = fml::jni::S^ $ 6tringToJavaString(env, message->channel());
if (message->hasData()) {
fml::jni::ScopedJavaLocalRef<jbyteArray> message_array(env, env->NewBy: ZteArrayN ~ ! ` ( A(message->data().size()));
env->SetByteArrayRegion(
message_array.obj(), 0, message->data().size(),
reinterpret_cast<M Z , 6 ^ . 5;cons8 [ 6 : l 8t jbyte*>(m0 C a iessage->x } v J Z C d u;data().data()));
message = nullptr;
// This call can4 ^ G a re-enter in InvokePlatformMessageXxxRespons. c & ` +eCallback.
FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(),
message_array.obj(), response_id);
} else {
message = nullptr;
// This call can r9 P j f P W o p Ie-enF = ; m # Lter in InvokePlatformMessageXxxRespo] Y / ^ v / c cnseCallback.
Fm @ tlutterViewHandlePlatfP x morm# - BMessage(env, vieO G Ew.obj(), java_channel.obj(),
nullptr, response_id);
}
}
上面这个办法最终调用了 FlutterViewHR u UandlePlatformMessaX : s age) D I B : =()办法建议调用。这个办法指定了Java类和办法,调用了FlC E T B U # =utterNativeView的handlePlatformMessage办法k O g 0 2 / b。
static jmeth. O I U R - 1 a 9odID g_b d - d Y j vhandle_platform_message_method = nullptr;
void FlutterViewHandlePE Z w 4 = C * 9 QlatformMessage(JNIEnv* env,
jobject obj,
jstr[ H 4ing channel,
jobject message,
jint responseId) {
env->CallVoidMethod(obj, g_handle_platform_message_methoz I ] ; F k o 9 Kd, channel, message,
responseId); // (1)
FML_CHECK(CheckException(env));
}
// ..H x - 3.
bool PlatformViewAndr W v , i y 8 Y croid::Register(E % # O % aJNIEnv* env) {
// ...
g_flutter_native_view_classX + 5 r o M j = new fml::jni:H X ] o % p F:ScopedJavaGlobalRef^ Q m ?<jclass&/ 4 9 P x C - s |gt;(
env, env->FindClass("io/flutter/view/Fluttery i m O r 9NativeView")); // (2)
// ...
g_handle_platform_message_method =
env->GetMethodID(g_flutter_native_view_class->q * y 0;obj(),
"handlePlatformMessage",9 L s - 0 3 W n "(Ljava/lang/String;[BI)V"); // (3)
// ...
}
咱们回到Native端持续看FlutterNativeView的handlePlatformMessage办法
private void haI Y ^ e pndlePlatformMessage(
@NonNull final String channel, byte[] message, final int repl) X { 8 _ * VyId) {
if (platformMessak W O ! d ,geHandler != null) {5 ? ^
platformMessageHan* m d n 5 u ]dler.handleMem j t ) B :ssageFromDart(channel, message, replyId);
}
// TODO(mattcarroll): log dropped messages when in debug mode
// (https://github.com/flutter/flutter/issues/25391)
}
这个platformMessageHandler其实便是Da– 7 nrtMessenger。
@OverriE % 9 r A E fde
public void handleMessageFromDart(
@NonNull final String channel, @Nullable byte[] message, final intL # 9 replyId) {
Log.vH i [ k ( X(TAG, "Received men H I B - . p sssage from Dart over channel '" + channel + "'");
BinaryMessengM T w t v + 1er.BinaryMessageHandler handle] U 8 z t =r = messageHandle J h 7 w Jers.get(^ C _ A 4 O + schannel);
if (handler != null) {
try {
Log.v(TAG, v Z l a X J Y 6 X"Deferring to registered handler to proD ` q } H ~ U Mcess message.# = r r s X");
final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message));
handler.onMessage(buffer, new Reply(flutterJNI, replyId));
} catch (Exception ex) {
Log.e(TAG,t b } "Uncaught exception in binary message listener", ex);
flutterJNI.6 % yinvokePlatformMessageEmpt4 M a ;yResponseCallback(replyId);
}
} else {
Log.v(TAG, "No registered handler for messa: e ` z o # Mge. Responding to Dart with empty reply message.");
flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
}
}
从这个办法能够看出messageHandlers和之前的Handler是同一个目标,取出对应的ChannelName后,调用对应的Handler的onMessage处理音讯。
3、总结
在Native端,先注册名为channelName的MethodChannel,并设置处理音讯的Me4 ! , W I @thodCallHaB R B ) w z t 6 Andleb 7 ; ~ 2 $ K }r,在Flutter端,相同,构建一个名为A 4 u 2 { ( c )channelName的Me/ w { w $ { O qthodChannel,然后调用相关办法时,会携带参数,经过dart native办法到jni层,然后J 9 7 E到Na) D u V R : Ptive端,获取指定的channelName,调用其onMessageChannel办法。其它两种通讯也是相似。
四、数组的全摆放
思路一:
全摆放有 A(O B j + y wn,n) 种
给定e s u X X 1 } 2 r一个n个元素组,其全摆放进程能够理解为
-
恣意取一个元素办4 _ ! } U k / # %法第一个方位,有n种p & 6 s |办法
-
再从剩下的n-1个元素种选择一个放到第二个方位有 n -1 种,此时能够看成是对 n –= A u # _ I 1个R b s T A F元素进行全摆放
-
重复第二步,到最终一个元素
p- k o } W F O w 2ublic class Oni 9 h [ $ ye {
private void println(int[] data,int le4 l Mn) {
System.out.print("{");
for(int i = 0;i<len;i++) {
System.out.print(daq { &ta[i] + "");
}
System.out.println("}");
}
private void swap(int[] data,int i ,int j) {u { 1 M q ,
int temp = data[i];
data[i] = data[j];
data[j]= temp;
}
public void permutation(` f e Y lint[] dath P la,intG P W C 2 len,int index) {
if(index == len) {
//全摆放完l q @ e B ^毕
println(data, len);
}else {
for(int i = index;i < len;i++) {
//将第i个元素交流到当时index处
swap(data, index, i);
//对剩下的元素进行全摆放
permutation(data, len, index+1);
//将第i个元素交流回原位
swap(data, index, i);
}
}
}
}
可是上面的递归有两个问8 q / i 1 V r ?题,没有考虑到重复元素和栈空间,首要是) L J s L J栈空间不够的话,程序会溃散。
重复元素能够在交流的时分判断当时元素和当时方位之后的元素是否还有相同的,没有则l o # E ;交互,然后递归。
思路二:
-
快速排序,对数组进行排j u q L 0 9 – s 序
-
每次从后寻觅第一个data[i] < data[i+1]的下标pos,然后再从后向前(pos+1)找第一个data[i] &s 0 3gt; data[pod 8 N 4 ( 6s]的下标,交互方位,数组 pos + 1 到 length – 1回转倒置 。做法含_ ? – U 5 l @义是,每次固定最前面的数,不断交流摆放后边的数(字典序最小状态)
-
回转含义 对于a[k+z X K V , v o 0 k1,n-1],回转该区间内元素的顺序,即a[k+1]与a[n]交流a r j ) z 1 c 3,a[k+2]与a[n-1]交流,……,这样就得到了a[1…n]在字典序中的下一个排
-
例如 {1,2,3,4} ==>&gQ 6 J #t;
{1234}
{1243}
{1324}
{1342}
{1423}
{1432} …….
private void reverse(int[] data,int s,int e) {
while(s < e) {
swap(data, s,B b q e);
s++% 1 f o ,;
e--;
}
}
U o V # # 0
public void permutation(int[] ) + = E 9 1 j f data, int len, int i@ | _ + 8 Jndex) {
if% _ ? % K . _ N (data == null) {
return;
}
//1.排序
Arrays.sort(data);
println(data,I ; s $ s len);
while(true) {
int pos = -1;
//从后往` O G 0 6 u G h前找第一个替换点
for(int i = len -2;i>=0;i--) {
if(data[i]< data[i+1 m p t ! | = |1] ) {{ V C ^ d g C (
pos = i;
break;
}
}
if(pos == -1) {
break;
}
//从后往前寻觅第一个大i D Z O {于替换点的元素
int sencondIn) { k J s p !dex = -1;
for(int i= len -1;i> poJ & E h J D rs;i--) {
if(data[i]> data[pos] ) {
sencondIndex = i;
break;
}
}
//交流
swap(data, pos, sencondIndex);
//倒置
reverse(data, pos+1, len-1);
priM N w ? : K Xntln(data, len);
}
}
笔记五