專案背景
本人前段時間負責公司一個Android SDK開發作業,并制定相關對接檔案,開發完成之后,與一些合作方對接,
但是某些公司的專案是用Flutter撰寫,需要撰寫對應SDK的flutter插件提供給對方,啥?flutter?不會呀!
哈哈哈,但是作為無所畏懼的程式員來說,能認慫么,當然是不能(硬著頭皮上)
最終一周內,將對應的Flutter插件開發完成并交付,以下是我學習開發Android SDK Flutter插件的總結
總結
萬事都是開頭難,但是在flutter大環境已經很成熟的情況下,完全不用慌,
第一步是弄明白flutter如何呼叫android原生代碼
推薦一篇博客,還有很多好的博客可以自行搜索:https://developer.aliyun.com/article/697792
還有一個我認為寫的比較好的開源flutter插件,可以拿來借鑒:https://github.com/OpenFlutter/Pangolin
安裝環境
在 Windows 作業系統上安裝和配置 Flutter 開發環境
創建插件專案
環境搭建完畢之后,打開Android studio ->File->new->new Flutter Project ->選擇Flutter Plugin
創建成功之后,打開專案,看到這樣的目錄結構,我們更多關心的是寫Android插件地方

撰寫插件

我們打開android目錄下的FlutterPlugin檔案,這是專案自己為我們生成的插件Demo,在這個視窗下,我們不難發現很多android原生代碼會爆紅,雖然不影響編譯,
但是看著很難受,我們選擇右上角Open for Editing in Android Studio,選擇在另一個視窗打開就沒事了,
我們看下它為我們自動生成的插件代碼,這里是Kotlin語法,它實作了FlutterPlugin,MethodCallHandler
/** FlutterPlugin */
public class FlutterPlugin: FlutterPlugin, MethodCallHandler {
...
private lateinit var channel : MethodChannel
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "flutter_plugin")
channel.setMethodCallHandler(this);
}
...
companion object {
@JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "flutter_plugin")
channel.setMethodCallHandler(FlutterPlugin())
}
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else {
result.notImplemented()
}
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}
其中,MethodCallHandler這個介面實作的onMethodCall(MethodCall call, MethodChannel.Result result) - 用于接受訊息,
這里接收的訊息就是來自于Flutter專案,call是訊息內容,它有兩個成員變數String型別的call.method表示呼叫的方法名,
Object 型別的call.arguments表示呼叫方法所傳遞的入參,
開始編碼,在android的目錄下的build.gradle加入我們自己Android專案的SDK依賴:
implementation 'com.jayxu.android:***Sdk:1.0.1'
在自動生成的插件代碼的基礎上,進行我們專案的開發,在插件里,我還需要拿到當前的activity物件,用于原生Activity之間的跳轉,
所以我還實作了ActivityAware,具體使用,請看代碼(Kotlin寫法),
/** PedesxpluginPlugin */
public class PedesxpluginPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
...
private lateinit var channel: MethodChannel
private lateinit var applicationContext: Context
private lateinit var activity: Activity
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
onAttachedToEngine(flutterPluginBinding.applicationContext, flutterPluginBinding.binaryMessenger)
}
fun onAttachedToEngine(applicationContext: Context, messenger: BinaryMessenger) {
this.applicationContext = applicationContext
channel = MethodChannel(messenger, "pedesxplugin")
channel.setMethodCallHandler(this)
}
fun onAttachedToEngine(applicationContext: Context, messenger: BinaryMessenger, activity: Activity) {
this.applicationContext = applicationContext
channel = MethodChannel(messenger, "pedesxplugin")
channel.setMethodCallHandler(this)
this.activity = activity
}
...
companion object {
@JvmStatic
fun registerWith(registrar: Registrar) {
val instance = PedesxpluginPlugin()
instance.onAttachedToEngine(registrar.context(), registrar.messenger(), registrar.activity())
}
}
/**
* 最主要的回呼方法
*/
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else if (call.method == "registerPedesx") {
val appId: String? = call.argument("appId")
val shelf_id: String? = call.argument("shelf_id")
val csj_appId: String? = call.argument("csj_appId")
val csj_video_id: String? = call.argument("csj_video_id")
//初始化SDK
PedesxUtil.init(applicationContext, appId, shelf_id, csj_appId, csj_video_id)
} else if (call.method == "registerPedesxUser") {
val uid: String? = call.argument("uid")
val oaid: String? = call.argument("oaid")
//初始化SDK的User資訊
PedesxUtil.initUser(applicationContext, uid, oaid)
} else if (call.method == "startPedesxVideoActivity") {
//跳轉我們自己SDK的界面1
ActivityUtils.startActivity(activity, Demo1Activity::class.java)
} else if (call.method == "startPedesxWelfareActivity") {
//跳轉我們自己SDK的界面2
ActivityUtils.startActivity(activity, Demo2Activity::class.java)
} else {
result.notImplemented()
}
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
override fun onDetachedFromActivity() {
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
this.activity = binding.activity
}
override fun onDetachedFromActivityForConfigChanges() {
}
}
到此Android 插件部分就全部寫好了,是不是很簡單,
如何使用插件
插件寫好了,那么Flutter專案如何使用我們的插件呢,我們的作業還在繼續
回到flutter插件專案,我們在lib目錄下,新建一個dart檔案,以下為代碼示例,沒有寫全,基本的寫法都差不多,這個檔案主要是將Android插件部分的代碼,再次封裝給我們的example專案使用,
...
MethodChannel _channel = MethodChannel('pedesxplugin')
..setMethodCallHandler(_methodHandler);
StreamController<BasePedesxResponse> _pedesxResponseEventHandlerController =
new StreamController.broadcast();
Stream<BasePedesxResponse> get pedesxResponseEventHandler =>
_pedesxResponseEventHandlerController.stream;
Future _methodHandler(MethodCall methodCall) {
var response =
BasePedesxResponse.create(methodCall.method, methodCall.arguments);
_pedesxResponseEventHandlerController.add(response);
return Future.value();
}
Future<bool> initPedesxSdk({
@required String appId, //SDK APPId
@required String shelf_id, //注釋1
@required String csj_appId, //注釋2
@required String csj_video_id, //注釋3
}) async {
return await _channel.invokeMethod("registerPedesx", {
"appId": appId,
"shelf_id": shelf_id,
"csj_appId": csj_appId,
"csj_video_id": csj_video_id,
});
}
Future<bool> initPedesxSdkUser({
@required String uid,
@required String oaid,
}) async {
return await _channel
.invokeMethod("registerPedesxUser", {"uid": uid, "oaid": oaid});
}
Future<bool> startPedesxVideoActivity() async {
return await _channel.invokeMethod("startPedesxVideoActivity");
}
Future<bool> startPedesxWelfareActivity() async {
return await _channel.invokeMethod("startPedesxWelfareActivity");
}
...
這里我們將Android插件的部分代碼與flutter呼叫插件的部分代碼進行比較,有沒有很清晰
android 插件代碼:
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
...
if (call.method == "registerPedesx") {
val appId: String? = call.argument("appId")
val shelf_id: String? = call.argument("shelf_id")
val csj_appId: String? = call.argument("csj_appId")
val csj_video_id: String? = call.argument("csj_video_id")
//初始化SDK
PedesxUtil.init(applicationContext, appId, shelf_id, csj_appId, csj_video_id)
}
...
}
-----------------------這是一條分界線---------------------------
flutter代碼:
Future<bool> initPedesxSdk({
@required String appId, //SDK APPId
@required String shelf_id, //貨架ID
@required String csj_appId, //穿山甲APPID
@required String csj_video_id, //穿山甲激勵視頻ID
}) async {
return await _channel.invokeMethod("registerPedesx", {
"appId": appId,
"shelf_id": shelf_id,
"csj_appId": csj_appId,
"csj_video_id": csj_video_id,
});
}
最終example專案呼叫插件的部分dart代碼:
_initPedesxSdk() async{
/**
* 初始化SDK
* appID:此為注釋
* shelf_id:此為注釋
* csjAppId:此為注釋
* codeId:此為注釋
*/
await Pedesxplugin.initPedesxSdk(
appId: "***",
shelf_id: "***********",
csj_appId: "*****",
csj_video_id: "*******",
);
}
因為部分代碼,涉及專案隱私,不能全部貼出,有問題童鞋的可以去看看https://github.com/OpenFlutter/Pangolin這個專案,強烈推薦,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/220642.html
標籤:其他
上一篇:HIVE教程
下一篇:蟠桃記 HDU - 2013
