某些場景下或者現有pub插件無法滿足我們的需求的時候需要自己寫一個插件
現在有這樣一個場景,需要給定一個圖片的url,然後下載圖片到指定目錄中(/storage/emulated/0/Android/data/com.zx.plugintest/files/Caches)。現在有一個插件,image_gallery_saver ,但它將網絡文件保存在了我們的相冊目錄中。
1、在flutter根目錄下新建一個flutter 插件
打開androidstudio terminal
flutter create --template=plugin --org com.zx --platforms=android,ios -a java -i swift save_img_plugin
其中
com.zx
是插件包名的一部分,save_img_plugin 是插件的名稱。插件的完整包名爲com.zx.save_img_plugin
爲什麼沒有使用IDE 的選項創建呢,我創建出來沒有android 和 ios的原生工程目錄
參考 https://blog.csdn.net/zytry/article/details/108997168
2、pubspec.yaml 添加插件
save_img_plugin:
path: save_img_plugin
pub get 一下
3、在插件的lib\save_pic_plugin.dart添加如下代碼
static Future saveImage(Uint8List imageBytes,
{int quality = 80, String name}) async {
assert(imageBytes != null);
final result =
await _channel.invokeMethod('saveImageToLocal', <String, dynamic>{
'imageBytes': imageBytes,
'quality': quality,
'name': name,
});
return result;
}
這裏的代碼是給其他flutter調用者 提供的外部接口。
4、實現native調用方法
package com.zx.save_img_plugin;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import androidx.annotation.NonNull;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import io.flutter.Log;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
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;
/** SaveImgPlugin */
public class SaveImgPlugin implements FlutterPlugin, MethodCallHandler {
private static final String TAG = "SaveImgPlugin";
private MethodChannel channel;
private Context mContext;
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "save_img_plugin");
channel.setMethodCallHandler(this);
mContext = flutterPluginBinding.getApplicationContext();
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
Log.d(TAG,"---onMethodCall---");
if (call.method.equals("saveImageToLocal")) {
byte[] image = null;
int quality = 100;
String name = "splash.jpg";
if (null != call.argument("imageBytes")) {
image = call.argument("imageBytes");
} else {
result.error("the argument imageBytes is null","","");
}
if (null != call.argument("name")) {
name = call.argument("name");
}
if (null != call.argument("quality")) {
quality = call.argument("quality");
if(quality <= 0 || quality>100) {
result.error("the quality is in range(0,100]","","");
}
}
result.success(saveImageToLocal(BitmapFactory.decodeByteArray(image,0,image.length), quality, name));
}
}
private boolean saveImageToLocal(Bitmap bmp, int quality, String name) {
Log.d(TAG,"---saveImageToLocal---");
Context context = mContext.getApplicationContext();
String cacheDir = context.getExternalFilesDir("Caches").getPath();
Log.d(TAG,"---cacheDir---" + cacheDir);
File file = new File(cacheDir + File.separator + name); //將圖片保存到剛創建好的目錄下
try {
FileOutputStream out = new FileOutputStream(file);
if (bmp != null) {
bmp.compress(Bitmap.CompressFormat.JPEG, quality, out);
}
out.close();
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
}
}
注意 :
1、flutter (save_pic_plugin.dart)傳遞的參數 saveImageToLocal 必須和 原生 if (call.method.equals("saveImageToLocal")) 中判斷的名稱相同才能進入對應邏輯。
2、平臺通道數據類型支持
平臺通道使用標準消息編/解碼器對消息進行編解碼,它可以高效的對消息進行二進制序列化與反序列化。由於Dart與原生平臺之間數據類型有所差異,下面我們列出數據類型之間的映射關係。
Dart | Android | iOS |
---|---|---|
null | null | nil (NSNull when nested) |
bool | java.lang.Boolean | NSNumber numberWithBool: |
int | java.lang.Integer | NSNumber numberWithInt: |
int, 如果不足32位 | java.lang.Long | NSNumber numberWithLong: |
int, 如果不足64位 | java.math.BigInteger | FlutterStandardBigInteger |
double | java.lang.Double | NSNumber numberWithDouble: |
String | java.lang.String | NSString |
Uint8List | byte[] | FlutterStandardTypedData typedDataWithBytes: |
Int32List | int[] | FlutterStandardTypedData typedDataWithInt32: |
Int64List | long[] | FlutterStandardTypedData typedDataWithInt64: |
Float64List | double[] | FlutterStandardTypedData typedDataWithFloat64: |
List | java.util.ArrayList | NSArray |
Map | java.util.HashMap | NSDictionary |
當在發送和接收值時,這些值在消息中的序列化和反序列化會自動進行。
在android 清單文件中添加兩個權限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.INTERNET"/>
至於權限怎麼添加和使用,方式如下:
5、新建一個permission.dart
import 'package:permission_handler/permission_handler.dart';
Future<bool> requestStoragePermission() async {
final storageStatus = await PermissionHandler().requestPermissions([PermissionGroup.storage]);
if (storageStatus[PermissionGroup.storage] == PermissionStatus.granted) {
return true;
} else {
return false;
}
}
6、使用
import 'Permission.dart' as Permission;
void savePic() async {
Permission.requestStoragePermission().then((value) async {
if(value) {
var response = await Dio().get(
"https://ss0.baidu.com/94o3dSag_xI4khGko9WTAnF6hhy/image/h%3D300/sign=a62e824376d98d1069d40a31113eb807/838ba61ea8d3fd1fc9c7b6853a4e251f94ca5f46.jpg",
options: Options(responseType: ResponseType.bytes));
SaveImgPlugin.saveImage(Uint8List.fromList(response.data),quality:100,name:'mypic1.png').then((value) {
setState(() {
tip = 'down load over';
});
});
}
});
}
完後在日誌中找到 ---cacheDir---/storage/emulated/0/Android/data/com.zx.plugintestapp/files/Caches ,這個裏面就有我們下載好的圖片文件。
ok,整個插件的基礎開發就是這些了。