開發流程:
1、使用object-c和java語言模板創建插件項目,command line : flutter create --template=plugin -i objc -a java mobile_state
關鍵文件:
//這裏是你的插件在dart 中引用的類文件,也就是銜接native的dart插件類
lib/mobile_state.dart
//這裏是你的插件對應的原生android文件
android/src/main/java/com/example/mobile_state/MobileStatePlugin.java
2、修改 lib/mobile_state.dart 下對應的 MethodChannel 與 invokeMethod() 方法中的參數
3、 通過invokeMethod() 方法發送的消息,在 java類文件中的 onMethodCall 方法中進行統一入口判斷與實現
4、通過result類返回信息傳遞給dart
5、本地引用插件
在項目的 pubspec.yml 文件的依賴部分聲明插件名稱,這裏的名稱必須和你插件項目中的 pubspec.yml 文件的 name 一致。
格式:
dependencies:
flutter:
sdk: flutter
[插件name]:
path: [插件的項目路徑,可用絕對或相對路徑]
參考:
dependencies:
flutter:
sdk: flutter
mobile_state:
path: /opt/coding/flutter/plugins/test/flutter_plugin_test/
注意事項:
1、因爲dart 語言和flutter 快速發展,在插件的java文件中,會有 onAttachedToEngine 和 registerWith 兩個方法,目的是將類註冊到dart對應的MethodChannel 中,
這兩個方法功能一致,在一個項目中,只會觸發其中一個方法,如果你使用的是 flutter >= 1.12.x ,則只會觸發 onAttachedToEngine方法,如果是 flutter <= 1.12.x 版本則會觸發 registerWith .
所以,當你在不同的版本中需要調用原生的交互時,特別要注意應該使用哪個方法進行原生調用。
2、關於 插件中引用 activity 的方式.
在 registerWith 方法中,通過方法參數中的 Registrar registrar 參數,進行獲取.
registrar.activity()
如果你是 1.12.x 版本,那麼在插件類中實現 ActivityAware 接口。
參考代碼:
public class MyPlugin implements FlutterPlugin, ActivityAware {
//...normal plugin behavior is hidden...
@Override
public void onAttachedToActivity(ActivityPluginBinding activityPluginBinding) {
// TODO: your plugin is now attached to an Activity
}
@Override
public void onDetachedFromActivityForConfigChanges() {
// TODO: the Activity your plugin was attached to was destroyed to change configuration.
// This call will be followed by onReattachedToActivityForConfigChanges().
}
@Override
public void onReattachedToActivityForConfigChanges(ActivityPluginBinding activityPluginBinding) {
// TODO: your plugin is now attached to a new Activity after a configuration change.
}
@Override
public void onDetachedFromActivity() {
// TODO: your plugin is no longer associated with an Activity. Clean up references.
}
}
參考鏈接: https://github.com/flutter/flutter/wiki/Experimental:-Create-Flutter-Plugin
3、關於插件中可能遇到的權限申請和檢查,則在拿到activity後按android 開發方式進行開發即可。
步驟:
1、首先需要向 AndroidMainfest.xml中添加權限
2、在申請權限的插件類中實現權限回調方法 onRequestPermissionsResult
3、然後再使用 ActivityCompat.requestPermissions 方法動態申請權限。
這裏注意一下權限申請方法參數的意義,對於一個新手,網上很多資料都沒有說明清楚。
權限申請方法: ActivityCompat.requestPermissions
參數列表:
參數 |
說明 |
Activity activity |
當前申請權限的 activity,在插件類中通過實現ActivityAware 接口獲取 |
String[] permissions |
申請權限數組,這個可以再網上找到android權限列表 |
int requestCode |
這個參數用於標識,哪個方法申請的權限,因爲權限處理均在一個方法中,可能很多處代碼均申請了權限,所以在處理時需要根據標識進行對應的返回結果處理。這個 requestCode 也會在 權限回調方法 onRequestPermissionsResult 中用上。 |
在插件中獲取手機號碼\IMEI等信息的完整參考代碼:
package com.example.mobile_state;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
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 io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import android.Manifest;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
/** MobileStatePlugin */
public class MobileStatePlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {
private static final int MY_PERMISSIONS_REQUEST_READ_PHONE_STATE = 0;
private static PluginRegistry.Registrar registrar;
private TelephonyManager telephonyManager;
static final String CHANNEL = "plugins.zcaij.com/mobile_state";
static Activity activity;
///activity 生命週期
@Override
public void onAttachedToActivity(ActivityPluginBinding activityPluginBinding) {
Log.e("onAttachedToActivity", "onAttachedToActivity");
activity = activityPluginBinding.getActivity();
}
@Override
public void onDetachedFromActivityForConfigChanges() {
Log.e("onDetachedFromActivityForConfigChanges", "onDetachedFromActivityForConfigChanges");
}
@Override
public void onReattachedToActivityForConfigChanges(ActivityPluginBinding activityPluginBinding) {
Log.e("onReattachedToActivityForConfigChanges", "onReattachedToActivityForConfigChanges");
}
@Override
public void onDetachedFromActivity() {
Log.e("onDetachedFromActivity", "onDetachedFromActivity");
}
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
final MethodChannel channel = new MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), CHANNEL);
channel.setMethodCallHandler(new MobileStatePlugin());
}
// This static function is optional and equivalent to onAttachedToEngine. It supports the old
// pre-Flutter-1.12 Android projects. You are encouraged to continue supporting
// plugin registration via this function while apps migrate to use the new Android APIs
// post-flutter-1.12 via https://flutter.dev/go/android-project-migration.
//
// It is encouraged to share logic between onAttachedToEngine and registerWith to keep
// them functionally equivalent. Only one of onAttachedToEngine or registerWith will be called
// depending on the user's project. onAttachedToEngine or registerWith must both be defined
// in the same class.
public static void registerWith(Registrar registrar) {
final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL);
channel.setMethodCallHandler(new MobileStatePlugin());
activity = registrar.activity();
}
void getNumber(){
String num = telephonyManager.getLine1Number();
Log.d("xxxxx",num);
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
telephonyManager = (TelephonyManager)activity.getSystemService(Context.TELEPHONY_SERVICE);
if (call.method.equals("getPhoneNumber")) {
int x = activity.checkSelfPermission(Manifest.permission.READ_PHONE_STATE);
if(x != 0)
{
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.READ_PHONE_STATE},
MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);
}else{
getNumber();
}
result.success("xxxxx");
} else {
result.notImplemented();
}
}
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_PHONE_STATE: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
getNumber();
}
return;
}
// other 'case' lines to check for other
// permissions this app might request.
}
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
}
}