前言
RepaintBoundary作为flutter截屏控件,截屏内容无法截取到带有播放器的播放内容页面,所以考虑调用安卓原生的截屏
插件目录结构
package net.bengkelrobot.flutter_native_screenshot;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Date;
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.embedding.engine.renderer.FlutterRenderer;
import io.flutter.plugin.common.BinaryMessenger;
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.Registrar;
import io.flutter.view.FlutterView;
/**
* FlutterNativeScreenshotPlugin
*/
public class FlutterNativeScreenshotPlugin
implements FlutterPlugin, MethodCallHandler, ActivityAware {
private static final String TAG = "FNSPlugin";
//声明context对象
private Context context;
//声明channel
private MethodChannel channel;
//声明context对象
private Activity activity;
//声明context对象
private Object renderer;
//声明状态
private boolean ssError = false;
//声明图片的路径
private String ssPath;
// Default constructor for old registrar
public FlutterNativeScreenshotPlugin() {
} // FlutterNativeScreenshotPlugin()
// Condensed logic to initialize the plugin
private void initPlugin(Context context, BinaryMessenger messenger, Activity activity,
Object renderer) {
this.context = context;
this.activity = activity;
this.renderer = renderer;
this.channel = new MethodChannel(messenger, "flutter_native_screenshot");
this.channel.setMethodCallHandler(this);
} // initPlugin()
//**************************注册插件******************************************
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
Log.println(Log.INFO, TAG, "Using *NEW* registrar method!");
initPlugin(
flutterPluginBinding.getApplicationContext(),
flutterPluginBinding.getBinaryMessenger(),
null,
flutterPluginBinding.getFlutterEngine().getRenderer()
); // initPlugin()
} // onAttachedToEngine()
// New v2 listener methods
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
this.channel.setMethodCallHandler(null);
this.channel = null;
this.context = null;
} // onDetachedFromEngine()
//旧的注册方法
//插件仍应包含静态的 registerWith() 方法,
//与不使用 v2 embedding 的应用程序保持兼容。
public static void registerWith(Registrar registrar) {
Log.println(Log.INFO, TAG, "Using *OLD* registrar method!");
FlutterNativeScreenshotPlugin instance = new FlutterNativeScreenshotPlugin();
instance.initPlugin(
registrar.context(),
registrar.messenger(),
registrar.activity(),
registrar.view()
); // initPlugin()
} // registerWith()
//***************************************在插件中引入activity对象***************
// Activity condensed methods
private void attachActivity(ActivityPluginBinding binding) {
//获取当前flutter页面所处的Activity.
this.activity = binding.getActivity();
} // attachActivity()
private void detachActivity() {
this.activity = null;
} // attachActivity()
// Activity listener methods
@Override
public void onAttachedToActivity(ActivityPluginBinding binding) {
attachActivity(binding);
} // onAttachedToActivity()
@Override
public void onDetachedFromActivityForConfigChanges() {
detachActivity();
} // onDetachedFromActivityForConfigChanges()
@Override
public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
attachActivity(binding);
} // onReattachedToActivityForConfigChanges()
@Override
public void onDetachedFromActivity() {
detachActivity();
} // onDetachedFromActivity()
//************************方法回调,这里主要是回调管道调用的方法***************************
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
if (!call.method.equals("takeScreenshot")) {
Log.println(Log.ERROR, TAG, "Method not implemented!");
result.notImplemented();
return;
}
takeScreenshotOld();
result.success(ssPath);
} // onMethodCall()
//*************************封装自己的方法*************************************
//用当前时间命名图片
private String getScreenshotName() {
java.text.SimpleDateFormat sf = new java.text.SimpleDateFormat("yyyyMMddHHmmss");
String sDate = sf.format(new Date());
return "flutter_native_screenshot-" + sDate + ".png";
} // getScreenshotName()
//获取
private String getScreenshotPath() {
String pathTemporary = context.getCacheDir().getPath();
Log.println(Log.INFO, TAG, "path temporary: " + pathTemporary);
String dirPath = pathTemporary + "/" + getScreenshotName();
Log.println(Log.INFO, TAG, "Built ScreeshotPath: " + dirPath);
return dirPath;
} // getScreenshotPath()
private String writeBitmap(Bitmap bitmap) {
try {
String path = getScreenshotPath();
File imageFile = new File(path);
FileOutputStream oStream = new FileOutputStream(imageFile);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, oStream);
oStream.flush();
oStream.close();
return path;
} catch (Exception ex) {
Log.println(Log.INFO, TAG, "Error writing bitmap: " + ex.getMessage());
}
return null;
} // writeBitmap()
private void reloadMedia() {
try {
//扫描媒体文件
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File file = new File(this.ssPath);
Uri uri = Uri.fromFile(file);
intent.setData(uri);
this.activity.sendBroadcast(intent);
} catch (Exception ex) {
Log.println(Log.INFO, TAG, "Error reloading media lib: " + ex.getMessage());
}
} // reloadMedia()
private void takeScreenshotOld() {
Log.println(Log.INFO, TAG, "Trying to take screenshot [old way]");
try {
//使用getWindow().getDecorView().getRootView()是获取当前屏幕的activity
View view = this.activity.getWindow().getDecorView().getRootView();
//从ImageView对象获取图像之前
view.setDrawingCacheEnabled(true);
Bitmap bitmap = null;
if (this.renderer.getClass() == FlutterView.class) {
bitmap = ((FlutterView) this.renderer).getBitmap();
} else if (this.renderer.getClass() == FlutterRenderer.class) {
bitmap = ((FlutterRenderer) this.renderer).getBitmap();
}
if (bitmap == null) {
this.ssError = true;
this.ssPath = null;
Log.println(Log.INFO, TAG, "The bitmap cannot be created :(");
return;
} // if
//从ImageView对象获取图像之后
view.setDrawingCacheEnabled(false);
//这样才能以清空画图缓冲区否则会导致下次还是上次的图
String path = writeBitmap(bitmap);
if (path == null || path.isEmpty()) {
this.ssError = true;
this.ssPath = null;
Log.println(Log.INFO, TAG, "The bitmap cannot be written, invalid path.");
return;
} // if
this.ssError = false;
this.ssPath = path;
reloadMedia();
} catch (Exception ex) {
Log.println(Log.INFO, TAG, "Error taking screenshot: " + ex.getMessage());
}
} // takeScreenshot()
}
AndroidManifest.xml的配置
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.bengkelrobot.flutter_native_screenshot">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
在lib封装
import 'dart:async';
import 'package:flutter/services.dart';
/// Class to capture screenshots with native code working on background
class FlutterNativeScreenshot {
static const MethodChannel _channel = const MethodChannel('flutter_native_screenshot');
/// Captures everything as is shown in user's device.
///
/// Returns [null] if an error occurs.
/// Returns a [String] with the path of the screenshot.
static Future<String> takeScreenshot() async {
final String path = await _channel.invokeMethod('takeScreenshot');
return path;
}
}
总结
可用,简单 调用方法 import之后 String path = await FlutterNativeScreenshot .takeScreenshot();
如果还需要做后续处理比如说将文件数据读取出来 可以作为image,或者盒子背景或者通过dio上传到网上
//提醒一下:这里的widget.picturePath实际上是上述的path
File _dataFile = File(widget.picturePath);
Uint8List _screenImgData = await _dataFile.readAsBytesSync();
//在widget那里可以通过
Image.memory(_screenImgData);
//或者作为盒子的背景
Container(
// decoration: BoxDecoration(color: Colors.white),
decoration: BoxDecoration(
image: DecorationImage(
image: MemoryImage(
_screenImgData,
),
fit: BoxFit.fill)),
)
//或者上传(这里的 NetUtils.postFormData实际上是对dio进行了一层封装)
NetUtils.postFormData(
Api.saveOrshareImg,
{"file": await MultipartFile.fromFile(widget.picturePath, filename: 'save.png')},
success: (response) {
print(response);
var jsonData = json.decode(response);
var res = ResponseModel.fromJson(jsonData);
if (res.status == 0) {;
print('success');
// }
} else {
print("${res.info.detail}${res.info.message}");
}
},
fail: (e) {
print(e.toString());
},
);
最开始命令行创建 flutter create --org com.example --template=plugin --platforms=android,ios -a java 插件名字
|