为了方便Android和iOS移动开发,Google推出了Flutter。Flutter和Xamarin,Cordova的概念相似 - 使用一种编程语言为多个平台开发。Flutter使用Dart。不过当使用第三方SDK的时候,Flutter依然需要用到Java或者Objective-C来写后台代码。
添加Android AAR
下载Flutter源码。
选择一个aar文件,我这里用DynamsoftBarcodeReader.aar。
把目录flutter/examples/hello_services/android/导入到Android Studio中。
点击File > New > New Module,选择Import .JAR/.AAR Package,添加AAR文件。打开工程属性,添加依赖模块就可以了。
Flutter UI与Java后台
打开AndroidManifest.xml 添加权限。
使用Java代码调用aar中的接口,然后把结果通过消息的形式发送到Flutter UI。
private String onGetBarcode(String json) {
String filename;
try {
JSONObject message = new JSONObject(json);
filename = message.getString("filename");
} catch (JSONException e) {
Log.e(TAG, "JSON exception", e);
return null;
}
String locationProvider;
String barcodeResult = "No barcode detected";
File file = new File(filename);
if (!file.exists()) {
barcodeResult = "No file exists: " + file.toString();
Toast.makeText(BarcodeReaderActivity.this, barcodeResult, Toast.LENGTH_LONG).show();
return null;
}
else {
Bitmap bitmap = BitmapFactory.decodeFile(file.toString());
BarcodeReader reader = new BarcodeReader("license");
ReadResult result = reader.readSingle(bitmap, Barcode.QR_CODE);
Barcode[] all = result.barcodes;
if (all != null && all.length == 1) {
barcodeResult = all[0].displayValue;
}
else {
barcodeResult = "no barcode found: " + file.toString();
}
bitmap.recycle();
}
JSONObject reply = new JSONObject();
try {
if (barcodeResult != null) {
reply.put("result", barcodeResult);
} else {
reply.put("result", "No barcode detected");
}
} catch (JSONException e) {
Log.e(TAG, "JSON exception", e);
return null;
}
return reply.toString();
}
创建Flutter Input, Button以及Text widgets:
@override
Widget build(BuildContext context) {
if (_isExisted) {
return new Material(
child: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Text('Barcode Reader'),
new Input(
labelText: 'Please input the image path',
value: new InputValue(text: _filename),
onChanged: onTextChanged,
autofocus: true,
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new RaisedButton(
child: new Text('Read'),
onPressed: _getBarcode
),
new RaisedButton(
child: new Text('Reset'),
onPressed: _resetResult
),
]
),
new Image.file(new File(_filename)),
new Text('$_result'),
]
)
)
);
}
else {
return new Material(
child: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Text('Barcode Reader'),
new Input(
labelText: 'Please input the image path',
onChanged: onTextChanged,
autofocus: true,
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new RaisedButton(
child: new Text('Read'),
onPressed: _getBarcode
),
new RaisedButton(
child: new Text('Reset'),
onPressed: _resetResult
),
]
),
new Text('$_result'),
]
)
)
);
}
}
Future<Null> _readBarcode() async {
final Map<String, String> message = <String, String>{'filename':_filename};
final Map<String, dynamic> reply = await HostMessages.sendJSON('getBarcode', message);
// If the widget was removed from the tree while the message was in flight,
// we want to discard the reply rather than calling setState to update our
// non-existent appearance.
if (!mounted)
return;
setState(() {
_result = reply['result'].toString();
});
}
运行程序:
参考资料
- accessing platform and third-party services in Flutter.
- Example of embedding Flutter using FlutterView
安装包问题
Flutter工程编译之后,会把libsky_shell.so打包到APK的armeabi-v7a目录中。我使用的aar文件还包含了arm64-v8a,编译之后会发现arm64-v8a目录中没有libsky_shell.so。这个时候如果APK安装到64位CPU的安卓设备上,会因为找不到libsky_shell.so导致程序崩溃无法启动。
解决的方法就是只保留armeabi-v7a的动态连接库,其余都删掉。