自己写一个flutter插件
某些场景下或者现有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', { '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 清单文件中添加两个权限
至于权限怎么添加和使用,方式如下:
5、新建一个permission.dart
import 'package:permission_handler/permission_handler.dart';Future 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,整个插件的基础开发就是这些了。
更多相关文章
- Android(安卓)Looper和Handler分析
- Android(安卓)wifi-framework WifiMonitor和WifiNative学习
- android消息机制(handler运行机制)解析
- android Handler,Looper,Message三者关系
- Android开发: 线程间消息通信 Looper 和Handler
- Android(安卓)开发中Parcel存储类型和数据容器
- Android动态换肤(二、apk免安装插件方式)
- Android(安卓)Studio学习之安装插件
- 即将到来的Android(安卓)N,将具备这些新特性