赞
踩
我的文章讲过:(0085)iOS开发之OC与JS交互高级用法(JavaScriptCore)
前言:我们知道OC 在UIWebView 加载 H5中,常常需要OC 与 H5 之间进行交互调用。采取的方法有:
- WebViewJavascriptBridge
- JavaScriptCore 框架
- 拦截URL
特征:都通过一种中间人进行桥接实现相互调用的。
今天讲的:Flutter与原生OC、Java的交互通信 也是一种桥接的方式实现的。类似WebViewJavascriptBridge、JavaScriptCore
的方式。Flutter 提供了 platform channels ,来和管理你的 Flutter view 的 ViewController 通信和交互数据。平台管道本质上是一个异步通信机制,桥接了 Dart 代码和宿主 ViewController,以及它运行于的 iOS 框架。你可以用平台管道来执行一个原生的函数,或者是从设备的传感器中获取数据。
本文翻译自官方文档:Writing custom platform-specific code
platform channel:平台通道
host;主机(这里指iOS 安卓端代码)
client:客户端(这里指Flutter端代码)
译文:
本指南介绍如何编写特定于平台的自定义代码。某些特定平台的功能可以通过现有的软件包获得;请参见using packages。
Flutter使用一个灵活的系统,允许您在Android平台上使用Java或Kotlin代码调用平台特定API,或者在Objective-C或Swift代码上调用iOS。
Flutter平台特定的API支持不依赖代码生成,而是依赖灵活的消息传递风格:
平台通道
向其host
(这个应用程序的iOS、Android部分)发送消息。host
通过平台通道
监听并接收消息。然后,它使用native programming language
调用任意数量特定平台的API,同时向client
(应用程序的flutter部分)发送响应。⚠️:如果您需要在Java/Kotlin/Objective-C or Swift中使用对应平台的APIs or libraries,本指南将使用
平台通道
机制来说明。但您也可以通过查看defaultTargetPlatform属性,在你的Flutter app中编写特定平台的Dart代码。Platform adaptations 在这个框架中Flutter自动帮我们做了一些特定平台的适配。
消息通过平台通道
在the client (UI) and host (platform) 之间传递,如图所示:
消息和响应是异步传递的,以确保用户界面保持响应。
⚠️注意:即使flutter异步地向Dart发送消息和从Dart接受消息,每当调用通道方法时,必须在平台的主线程上调用该方法。有关更多信息,请参阅线程部分。
On the client
side, MethodChannel (API)
能发送message
并能响应方法回调,On the platform
side,在Android 的(API)MethodChannel
和iOS的(API) FlutterMethodChannel
能接收到方法调用并返回一个结果。这些类允许您用很少的“样板”代码开发平台插件。
补充:如果需要,方法调用也可以反向发送消息,用平台充当客户端在Dart中实现方法。快速动作插件quick_actions就是一个具体的例子。
标准平台通道使用标准消息编解码器,该编解码器支持对类似于JSON的简单值(booleans, numbers, Strings, byte buffers, and List and Maps)进行有效的二进制序列化(有关详细信息,请参阅StandardMessageCodec编解码器)。当发送和接收值时,这些值与消息之间的序列化和反序列化将自动进行。
下表显示了如何在平台侧接收Dart值,反之亦然:
下面代码演示如何调用特定平台的API来取回并显示当前电池电量。它通过平台消息的一个消息getBatteryLevel()
来使用Android BatteryManager API
和ios device.batteryLevel API
实现的。
该示例将特定平台的代码添加到主应用程序本身中。如果您想为多个应用程序重用特定平台的代码,那么项目创建步骤略有不同(请参见开发包),但是平台通道代码仍然是以相同的方式编写的。
注意:这个例子的完整的可运行源代码(Android with Java and iOS with Objective-C)可以在/examples/platform_channel/找到。For iOS with Swift, see /examples/platform_channel_swift/。
这里我已经有一个工程hello,跳过此步。
a single platform method
来构造通道。通道的客户端和主机端通过通道构造函数中传递的通道名称连接。单个应用程序中使用的所有频道名称必须是唯一的;在频道名称前面加上唯一的“域前缀”,例如:samples.flutter.dev/battery
。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
...
class MethodChannelTestViewState extends State<MethodChannelTestView> {
static const platform = const MethodChannel('samples.flutter.dev/battery');
// Get battery level.
}
platform
调用invokeMethod
来调用一个字符串标识符为getBatteryLevel
一个具体方法。这个方法在特定平台实现。调用可能会失败,例如,如果平台不支持platform
API(例如在模拟器中运行时),因此请将invokeMethod
调用包装在try catch语句中。用返回的结果来更新setstate内电池级别的用户界面状态。
// Get battery level. String _batteryLevel = 'Unknown battery level.'; Future<void> _getBatteryLevel() async { String batteryLevel; try { final int result = await platform.invokeMethod('getBatteryLevel'); batteryLevel = 'Battery level at $result % .'; } on PlatformException catch (e) { batteryLevel = "Failed to get battery level: '${e.message}'."; } setState(() { _batteryLevel = batteryLevel; }); }
@override Widget build(BuildContext context) { return Material( child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ RaisedButton( child: Text('Get Battery Level'), onPressed: _getBatteryLevel, ), Text(_batteryLevel), ], ), ), ); }
注意:以下步骤使用Objective-C。如果您喜欢使用Swift,请跳到步骤4b。
首先在Xcode中打开flutter应用程序的iOS主机部分:
AppDelegate.m
AppDelegate.m
对应代码#import <Flutter/Flutter.h> #import "GeneratedPluginRegistrant.h" @implementation AppDelegate - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController; FlutterMethodChannel* batteryChannel = [FlutterMethodChannel methodChannelWithName:@"samples.flutter.dev/battery" binaryMessenger:controller]; [batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { // Note: this method is invoked on the UI thread. // TODO }]; [GeneratedPluginRegistrant registerWithRegistry:self]; return [super application:application didFinishLaunchingWithOptions:launchOptions]; }
AppDelegate
类中@end
之前添加以下方法:- (int)getBatteryLevel {
UIDevice* device = UIDevice.currentDevice;
device.batteryMonitoringEnabled = YES;
if (device.batteryState == UIDeviceBatteryStateUnknown) {
return -1;
} else {
return (int)(device.batteryLevel * 100);
}
}
setMethodCallHandler()
方法。您需要处理调用getBatteryLevel()
以此来测试返回的值,并使用result参数返回成功和错误情况的响应。如果调用了未知的方法,请报告该方法:unknown method is called
。__weak typeof(self) weakSelf = self [batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { // Note: this method is invoked on the UI thread. if ([@"getBatteryLevel" isEqualToString:call.method]) { int batteryLevel = [weakSelf getBatteryLevel]; if (batteryLevel == -1) { result([FlutterError errorWithCode:@"UNAVAILABLE" message:@"Battery info unavailable" details:nil]); } else { result(@(batteryLevel)); } } else { result(FlutterMethodNotImplemented); } }];
完成:您现在应该可以在iOS上运行该应用程序了。如果使用iOS模拟器,请注意它不支持电池API,并且应用程序显示“电池信息不可用”。
效果如下:这样就实现了Flutter与原生OC的通信。为了更好的验证。我还增加了一个方法getFromOCClientMessage
。
flutter:
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'dart:async'; class MethodChannelTest extends StatelessWidget { @override Widget build(BuildContext context) { // TODO: implement build return MethodChannelTestView(); } } class MethodChannelTestView extends StatefulWidget { @override State<StatefulWidget> createState() { // TODO: implement createState return MethodChannelTestViewState(); } } class MethodChannelTestViewState extends State <MethodChannelTestView> { static const platform = const MethodChannel('samples.flutter.dev/battery'); final textColorStyle = TextStyle(color: Colors.deepOrange); // Get battery level. String _batteryLevel = 'Unknown battery level.'; // 测试从OC 端传过来的字符串 String _messageFromOC = '默认Flutter'; Future<void> _getBatteryLevel() async { String batteryLevel; try { final int result = await platform.invokeMethod('getBatteryLevel'); batteryLevel = 'Battery level at $result % .'; } on PlatformException catch (e) { batteryLevel = "Failed to get battery level: '${e.message}'."; } print(batteryLevel); setState(() { _batteryLevel = batteryLevel; }); } // 测试Flutter 与OC 端通信 Future<void> _getFromOCClientMessage () async { String message; try { final String result = await platform.invokeMethod('getFromOCClientMessage'); message = 'Message 来自 $result % .'; } on PlatformException catch (e) { message = "Failed to get Message: '${e.message}'."; } print('我获取到从OC 传过来的值 :$message'); setState(() { _messageFromOC = message; }); } void _pushSaved() { print('你哈后!'); } @override Widget build(BuildContext context) { // TODO: implement build return Scaffold( appBar: AppBar( title: Text('我的收藏列表'), actions: <Widget>[ new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved), ], ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ RaisedButton( child: Text('Get Battery Level'), onPressed: _getBatteryLevel, ), Text(_batteryLevel,style: textColorStyle), SizedBox( height: 40, ), RaisedButton( child: Text('Get Message From OC'), onPressed: _getFromOCClientMessage, ), Text(_messageFromOC,style: textColorStyle,), ], ), ), ); } }
OC 端代码:
#include "AppDelegate.h" #include "GeneratedPluginRegistrant.h" @implementation AppDelegate - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { FlutterViewController *controller = (FlutterViewController *)self.window.rootViewController; FlutterMethodChannel *batteryChannel = [FlutterMethodChannel methodChannelWithName:@"samples.flutter.dev/battery" binaryMessenger:controller]; __weak typeof(self) weakSelf = self; [batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { // Note: this method is invoked on the UI thread. if ([@"getBatteryLevel" isEqualToString:call.method]) { int batteryLevel = [weakSelf getBatteryLevel]; if (batteryLevel == -1) { result([FlutterError errorWithCode:@"UNAVAILABLE" message:@"Battery info unavailable" details:nil]); } else { result(@(batteryLevel)); } } else if ([@"getFromOCClientMessage" isEqualToString:call.method]) { NSString *testMethod = [weakSelf getFromOCClientMessage]; result(testMethod); } else { result(FlutterMethodNotImplemented); } }]; [GeneratedPluginRegistrant registerWithRegistry:self]; return [super application:application didFinishLaunchingWithOptions:launchOptions]; } - (int)getBatteryLevel { UIDevice* device = UIDevice.currentDevice; device.batteryMonitoringEnabled = YES; if (device.batteryState == UIDeviceBatteryStateUnknown) { return -1; } else { return (int)(device.batteryLevel * 100); } } - (NSString *)getFromOCClientMessage { return @"我来自OC client!!!"; } @end
不再翻译和Step 4a 相同。只是改用swift语法实现即可。
同理:
MainActivity.java
MainActivity.java
对应代码import io.flutter.app.FlutterActivity; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; public class MainActivity extends FlutterActivity { private static final String CHANNEL = "samples.flutter.dev/battery"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(this); new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler( new MethodCallHandler() { @Override public void onMethodCall(MethodCall call, Result result) { // Note: this method is invoked on the main thread. // TODO } }); } }
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
private int getBatteryLevel() {
int batteryLevel = -1;
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
} else {
Intent intent = new ContextWrapper(getApplicationContext()).
registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
}
return batteryLevel;
}
setMethodCallHandler()
方法。您需要处理调用getBatteryLevel()
以此来测试返回的值,并使用result参数返回成功和错误情况的响应。如果调用了未知的方法,请报告该方法:unknown method is called
。@Override
public void onMethodCall(MethodCall call, Result result) {
// Note: this method is invoked on the main thread.
if (call.method.equals("getBatteryLevel")) {
int batteryLevel = getBatteryLevel();
if (batteryLevel != -1) {
result.success(batteryLevel);
} else {
result.error("UNAVAILABLE", "Battery level not available.", null);
}
} else {
result.notImplemented();
}
}
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'dart:async'; class MethodChannelTest extends StatelessWidget { @override Widget build(BuildContext context) { // TODO: implement build return MethodChannelTestView(); } } class MethodChannelTestView extends StatefulWidget { @override State<StatefulWidget> createState() { // TODO: implement createState return MethodChannelTestViewState(); } } class MethodChannelTestViewState extends State <MethodChannelTestView> { static const platform = const MethodChannel('samples.flutter.dev/battery'); final textColorStyle = TextStyle(color: Colors.deepOrange); // Get battery level. String _batteryLevel = 'Unknown battery level.'; // 测试从OC 端传过来的字符串 String _messageFromOC = '默认Flutter'; // 测试从AD 端传过来的字符串 String _messageFromAD = '默认Flutter'; Future<void> _getBatteryLevel() async { String batteryLevel; try { final int result = await platform.invokeMethod('getBatteryLevel'); batteryLevel = 'Battery level at $result % .'; } on PlatformException catch (e) { batteryLevel = "Failed to get battery level: '${e.message}'."; } print(batteryLevel); setState(() { _batteryLevel = batteryLevel; }); } // 测试Flutter 与OC 端通信 Future<void> _getFromOCClientMessage () async { String message; try { final String result = await platform.invokeMethod('getFromOCClientMessage'); message = 'Message 来自 $result % .'; } on PlatformException catch (e) { message = "Failed to get Message: '${e.message}'."; } print('我获取到从OC 传过来的值 :$message'); setState(() { _messageFromOC = message; }); } // 测试Flutter 与AD 端通信 Future<void> _getFromADClientMessage () async { String message; try { final String result = await platform.invokeMethod('getFromADClientMessage'); message = 'Message 来自 $result % .'; } on PlatformException catch (e) { message = "Failed to get Message: '${e.message}'."; } print('我获取到从AD 传过来的值 :$message'); setState(() { _messageFromAD = message; }); } void _pushSaved() { print('你哈后!'); } @override Widget build(BuildContext context) { // TODO: implement build return Scaffold( appBar: AppBar( title: Text('我的收藏列表'), actions: <Widget>[ new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved), ], ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ RaisedButton( child: Text('Get Battery Level'), onPressed: _getBatteryLevel, ), Text(_batteryLevel,style: textColorStyle), SizedBox( height: 40, ), RaisedButton( child: Text('Get Message From OC'), onPressed: _getFromOCClientMessage, ), Text(_messageFromOC,style: textColorStyle,), SizedBox( height: 40, ), RaisedButton( child: Text('Get Message From Andriod'), onPressed: _getFromADClientMessage, ), Text(_messageFromAD,style: textColorStyle,), ], ), ), ); } }
Java 端
package com.example.hello; import android.os.Bundle; import io.flutter.app.FlutterActivity; import io.flutter.plugins.GeneratedPluginRegistrant; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentFilter; import android.os.BatteryManager; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; import android.util.Log; public class MainActivity extends FlutterActivity { private static final String CHANNEL = "samples.flutter.dev/battery"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler( new MethodCallHandler() { public void onMethodCall(MethodCall call, Result result) { String method = call.method; //Log.d(method, "The onStart() event"); if (call.method.equals("getBatteryLevel")) { int batteryLevel = getBatteryLevel(); if (batteryLevel != -1) { result.success(batteryLevel); } else { result.error("UNAVAILABLE", "Battery level not available.", null); } } else if (call.method.equals("getFromADClientMessage")) { String message = getFromADClientMessage(); result.success(message) ; } else { result.notImplemented(); } } }); GeneratedPluginRegistrant.registerWith(this); } private int getBatteryLevel() { int batteryLevel = -1; if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE); batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); } else { Intent intent = new ContextWrapper(getApplicationContext()). registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); } return batteryLevel; } private String getFromADClientMessage() { return "我来自Android"; } }
效果如图:
完成了Flutter与原生OC、Java的交互通信!???!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。