1. 两个插件之间冲突(target has frameworks with conflicting names)
问题背景:本地插件和项目引用的插件中引用的插件之间有冲突,如:本地插件amap_location_flutter_plugin和远程插件amap_map_fluttify
-
解决思路:
1、将amap_map_fluttify放到amap_location_flutter_plugin中的dependency_overrides下面,如果需要,可以在本地插件里面将amap_map_fluttify内容export到项目中使用;最终发现在iOS中pod根本不会下载map的库,这个overrides只对当前module有效,所以该思路不通;2、将两个插件手动合并成一个插件来避免冲突,我是将amap_location_flutter_plugin中的内容放到了fluttify中,因为location中的内容较少也比较简单。在合并的过程中碰到了两个问题:1. 注册插件的问题;2. 包引用的问题;这个两个问题主要在Android项目上。
在iOS很好解决因为我本身是iOS开发。iOS里面引用包的方式变成本地引用的方式就好,注册就直接在map中的register方法中调用location中plugin类的register就好了;
在Android里面就有意思了,因为注册插件的时候有两种方式,第一种是用register,第二种就是onAttachedToEngine,而安卓就是用的第二种,这好像是新版本的方式,也是在map的插件类中的onAttachedToEngine中binding.getFlutterEngine().getPlugins().add(new AmapLocationFlutterPlugin());
关于包引用在Android根本不用改,很丝滑;
在解决插件注册的时候了解到,flutter和原生交互的通道包括MethodChannel和EventChannel,前者是双向的交互,后者是单向的,既只支持原生端到flutter端,使用场景比如定位的实时获取,原生端将位置信息不停的将数据发送给flutter;
2. 将flutter老版本项目升级到2.0以上
- 大概是以下几步:
- 主要是适配非空安全,这个在项目运行配置里面additional run args: --no-sound-null-safety;
- 升级一些版本低的插件,pub get的时候会有提示,还有一种办法就是在项目目录下用命令flutter pub add 库名,这种方式会自动下载一个合适的版本;
- 其他问题,比如我就碰到了问题1的插件冲突问题;
3. webView 和原生交互
- js调用flutter
- 使用插件webview_flutter,
- iOS端在info.plist文件中配置<key>io.flutter.embedded_views_preview</key>
<true/> - 注入channels,使用js能够调用
JavascriptChannel(
name: "NativeShare",
onMessageReceived: (message) {
print("收到web端消息: $message");
// shareToWeChat(WeChatShareMiniProgramModel(webPageUrl: "webPageUrl", userName: ""));
}),
然后再js中需要地方调用
NativeShare.postMessage(JSON.stringify({}));
- flutter调用js
使用WebViewController对象执行;
4. QQ分享的图片地址转uri
Uri.parse("图片地址")
5. flutter中webview跳转安卓微信支付失败
开发环境:flutter 2.8.0 webview_flutter 3.0.0
一直会提示参数错误,主要是因为解析不出weixin://协议头的url,必须在加载微信支付url的时候在header中传入对应的微信支付平台授权的域名;
// 在拦截链接地时候重新加载
if (request.url.startsWith("https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb") && Platform.isAndroid) {
// 安卓平台必须传入对应微信平台的授权域名
_webViewController?.loadUrl(request.url, headers: {"Referer" : Uri.parse(controller.url).scheme + "://" + Uri.parse(controller.url).host});
return NavigationDecision.prevent;
}
6. 分享到微信小程序
username要传原始ID,在小程序管理后台可以找到
7. 只生成release模式的framework和aar
flutter build ios-framework --no-debug --no-profile --output=./.framework/ios/
flutter build aar --no-profile --no-debug --build-number x.x.x
8. 发送全局事件(通知)
依赖插件event_bus;
定义:
EventBus eventBus = EventBus();
enum TaskHallEventType {
// 列表 下拉刷新 通知 刷新 勋章数量 滚动消息
on_refresh,
// 推送进入任务详情页
on_enter_task_detail_page,
}
///任务大厅相关事件通知
class TaskHallEventMessage {
Map<Object?, Object?>? parameters;
TaskHallEventType eventType;
TaskHallEventMessage(this.eventType, {this.parameters});
}
使用:
#发送事件
eventBus.fire(TaskHallEventMessage(TaskHallEventType.on_enter_task_detail_page, parameters: notificationInfo));
#监听事件
// 定义的监听对象需要再销毁的时候进行释放
_taskHallListOnRefreshSubscription = eventBus.on<TaskHallEventMessage>().listen((event) {
if (event.eventType == TaskHallEventType.on_refresh) {
///获取学生勋章数
loadMedalCount();
///获取滚动列表数据
loadScrollMsgList();
} else if (event.eventType == TaskHallEventType.on_enter_task_detail_page) {
if (event.parameters != null) {
naviToTaskDetailPage(event.parameters!);
}
}
});
void onClose() {
_taskHallListOnRefreshSubscription.cancle();
}
9. Get之Obx不刷新问题
#绑定
Obx(() {
return Text(
controller.isEditing.value == true ? "全选" : "删除",
style: TextStyle(
color: const Color(0xff3982FB),
ontSize: 15.ft,
fontWeight: FontWeight.w400
),
);
})
#改变
this.isEditing.value = false;
改变时是改变obs的value并不是赋值一个新的obs对象(this.isEditing = false.obs);看别人很多写的都是赋值新的obs对象,这样根本就刷新不了;
10. 报全局异常,只能提示错误的代码行,没有错误内容;
flutter版本:2.8.0
使用背景:请求接口返回的数据定义是个dynamic,然后使用map生成模型数组,在迭代期间没有问题,但是迭代完后却报错了,也不提示什么错误;
解决办法:将dynamic的变量转换成数组( as List) 再进行map就没问题了;
11. 两个Text中中文和数字对齐
解决: 将显示数字的Text种的style 中的height进行设置一般在1.5左右就能对齐;
12. 计算字符的高度
Size boundingTextSize(String text, TextStyle style,
{int maxLines = 2 ^ 31, double maxWidth = double.infinity}) {
if (text.isEmpty) {
return Size.zero;
}
final TextPainter textPainter = TextPainter(
textDirection: TextDirection.ltr,
text: TextSpan(text: text, style: style), maxLines: maxLines)
..layout(maxWidth: maxWidth);
return textPainter.size;
}
13. 日期选择空间显示中文
showDatePicker(context: ctx,builder: (BuildContext context, Widget? child) {
return Localizations(
locale: const Locale('zh'),
child: child,
delegates: <LocalizationsDelegate>[
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
]
);
}, initialDate: date, firstDate: date, lastDate: DateTime(date.year,date.month,date.day + 7)).then((value) {
state.date = value.toString().substring(0,10);
loadData(state.date);
});
14. 打包Windows平台安装包命令
项目先添加msix插件依赖
执行命令:dart run msix:create
Win7 需要使用inno setup 处理打包,它可以生成打包脚本,Flutter build好后,就可以用这个执行脚本打包成exe安装包;
15. Windows插件制作时,插件中依赖其他的dll,只需要在set的时候 变量名称符合规则,dll就会被拷贝到生成目录。
具体写法如下:
16. Windows平台运行时偶现报错:C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(166,5): error MSB3073...
我目前的cmake版本是3.14,只要我把那个build文件删掉,再次编译就会报这个错误。找不到错误原因;
解决办法:用Visual studio打开build下面的Windows文件夹下的sin文件,重新生成一次解决方案,再回到flutter项目启动即可;
注:需要删除缓存的时候只把build下面的Windows文件夹删掉就行,再次构建就不会存在问题;
17. flutter抓包设置,在设置代理的时候Dio也需要一起初始化, 只需要在应用内设置代理的ip和端口并保持跟代理服务器在同一网段即可,无需其他配置;
reset({String? ip, String? port}) {
var baseUrl = AESStorageUtils.getString(SpConfigConstants.enConfig,
defaultValue: EnvironmentType.Environment_Production.value) +
Apis.kPathSuffix;
_dio = Dio(BaseOptions(
baseUrl: baseUrl, connectTimeout: RequestConfigure.connectTimeout));
_dio.interceptors.add(LogInterceptor(responseBody: true));
_dio.interceptors.add(TokenInterceptor());
_dio.interceptors.add(URLInterceptor());
if (ip != null && port != null) {
AESStorageUtils.saveString(SpConfigConstants.kProxy_ip, ip);
AESStorageUtils.saveString(SpConfigConstants.kProxy_port, port);
}
var local_ip = AESStorageUtils.getString(SpConfigConstants.kProxy_ip);
var local_port = AESStorageUtils.getString(SpConfigConstants.kProxy_port);
if (local_ip.isNotEmpty && local_port.isNotEmpty) {
(_dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient = () {
var client = HttpClient();
client.findProxy = (uri) {
return "PROXY $local_ip:$local_port";
};
client.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
return client;
};
}
}