1、Flutter 报错 Could not create task ‘xxx‘.this and base files have different roots
1、问题场景:此问题会出现在你的项目路径不在 C 盘(系统盘)或是不在 flutter sdk 所在盘符下。正常在 flutter 项目中运行没有问题,会出现在将 flutter 以 Android 项目打开。
看报错信息,属于是文件存在在了两个路径,它不知道咋整。可能是编译Android 项目时,默认会将第三方的缓存在系统盘。
2、解决办法:
方法一、把项目复制到和 flutter 相同的目录下,重新打开项目即可
方法二、a、在项目盘符下新建文件夹,正常命名(别整中文和特殊符号,flutter_pub_cache我觉得就不错),然后打开环境变量,新建或编辑系统环境变量,输入PUB_CACHE,然后将你刚才创建的文件路径填进去。
b、重启电脑
c、打开flutter 项目,flutter pub get,
d、打开 Android 项目,本次编译可能时间较长
原文链接:https://blog.csdn.net/LoveShadowing/article/details/132210526
2、shared_preferences
本地存储工具类,不限制string bool int list及list<Map>等结构
class Storage {
static setData(String key, dynamic value) async {
SharedPreferences pref = await SharedPreferences.getInstance();
pref.setString(key, json.encode(value));
}
static getData(String key) async {
SharedPreferences pref = await SharedPreferences.getInstance();
String? data = pref.getString(key);
return json.decode(data!);
}
static removeData(String key) async {
SharedPreferences pref = await SharedPreferences.getInstance();
return pref.remove(key);
}
}
其他基本使用
class _SharePreferenecesPagerState extends State<SharePreferenecesPager> {
final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
_saveData() async {
final prefs = await _prefs;
prefs.setString("username", "张三");
prefs.setInt("age", 20);
List<String> userinfo = ["张三", "李四", "王五"];
prefs.setStringList("userinfo", userinfo);
List<Map> newsList = [
{"title": "我是一个标题"},
{"title": "我是二个标题"},
];
prefs.setString("newsList", json.encode(newsList));
}
_getData() async {
final prefs = await _prefs;
String? username = prefs.getString("username");
print(username);
int? age = prefs.getInt("age");
print(age);
List<String>? list = prefs.getStringList("userinfo");
print(list);
print(list![0]);
//获取List<Map>
String? newsList = prefs.getString("newsList");
var tempData = json.decode(newsList!);
print(tempData[0]);
print(tempData[0]["title"]);
}
_removeData() async {
final prefs = await _prefs;
prefs.remove("username");
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Title'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: _saveData,
child: const Text('保存数据'),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: _getData,
child: const Text('获取数据'),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: _removeData,
child: const Text('清除数据'),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
Storage.setData("username", "李四");
},
child: const Text("设置String")),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
var username = await Storage.getData("username");
// print(username as String);
},
child: const Text("获取String")),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
List<Map> list = [
{"title": "一个新闻111", "author": "itying"},
{"title": "一个新闻", "author": "itying"},
{"title": "一个新闻", "author": "itying"},
];
Storage.setData("newslist", list);
},
child: const Text("设置List")),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
var list = await Storage.getData("newslist");
},
child: const Text("获取List数据")),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
Storage.setData("num", 123.4);
},
child: const Text("设置num数据")),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
var num = await Storage.getData("num");
},
child: const Text("获取num数据")),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
Storage.setData("flag", false);
},
child: const Text("设置bool数据")),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
var flag = await Storage.getData("flag");
},
child: const Text("获取bool数据")),
],
),
),
);
}
}
3、barcode_scan2可以实现扫描条形码、二维码
Android配置
<uses-permission android:name="android.permission.CAMERA" />
Ios里面的配置
<dict>
<!-- ... -->
<key>NSCameraUsageDescription</key>
<string>Camera permission is required for barcode scanning.</string>
<!-- ... -->
</dict>
基本使用
class _ScanPagerState extends State<ScanPager> {
late String scanData = "内容";
void doBarcodeScan() async {
var options = const ScanOptions(
// set the options
autoEnableFlash: true,
strings: {
'cancel': '取消',
'flash_on': '打开Flash',
'flash_off': '关闭Flash',
});
var result = await BarcodeScanner.scan(options: options);
print(result.type); // The result type (barcode, cancelled, failed)
print(result.rawContent); // The barcode content
print(result.format); // The barcode format (as enum)
print(result .formatNote); // If a unknown format was scanned this field contains a
setState(() {
scanData = result.rawContent;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("扫一扫")),
body: Center(
child: Column(children: [
Text(scanData),
const SizedBox(height: 20),
ElevatedButton(onPressed: doBarcodeScan, child: const Text("扫一扫"))
]),
),
);
}
}
4、地图定位实现
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:amap_flutter_location/amap_flutter_location.dart';
import 'package:amap_flutter_location/amap_location_option.dart';
import 'package:permission_handler/permission_handler.dart';
class GaodeMapLocation extends StatefulWidget {
const GaodeMapLocation({super.key});
@override
State<GaodeMapLocation> createState() => _GaodeMapLocationState();
}
class _GaodeMapLocationState extends State<GaodeMapLocation> {
String _latitude = ""; //纬度
String _longitude = ""; //经度
//监听定位
late StreamSubscription<Map<String, Object>> _locationListener;
//实例化插件
final AMapFlutterLocation _locationPlugin = AMapFlutterLocation();
@override
void initState() {
super.initState();
/// 动态申请定位权限
requestPermission();
AMapFlutterLocation.setApiKey(
"d21b99823c36665d5a2c1a06ee4a8186", "ios ApiKey");
///注册定位结果监听
_locationListener = _locationPlugin
.onLocationChanged()
.listen((Map<String, Object> result) {
setState(() {
print(result);
_latitude = result["latitude"].toString();
_longitude = result["longitude"].toString();
});
});
}
@override
void dispose() {
super.dispose();
///移除定位监听
if (null != _locationListener) {
_locationListener.cancel();
}
///销毁定位
if (null != _locationPlugin) {
_locationPlugin.destroy();
}
}
///设置定位参数
void _setLocationOption() {
if (null != _locationPlugin) {
AMapLocationOption locationOption = new AMapLocationOption();
///是否单次定位
locationOption.onceLocation = true;
///是否需要返回逆地理信息
locationOption.needAddress = true;
///逆地理信息的语言类型
locationOption.geoLanguage = GeoLanguage.DEFAULT;
locationOption.desiredLocationAccuracyAuthorizationMode =
AMapLocationAccuracyAuthorizationMode.ReduceAccuracy;
locationOption.fullAccuracyPurposeKey = "AMapLocationScene";
///设置Android端连续定位的定位间隔
locationOption.locationInterval = 2000;
///设置Android端的定位模式<br>
///可选值:<br>
///<li>[AMapLocationMode.Battery_Saving]</li>
///<li>[AMapLocationMode.Device_Sensors]</li>
///<li>[AMapLocationMode.Hight_Accuracy]</li>
locationOption.locationMode = AMapLocationMode.Hight_Accuracy;
///设置iOS端的定位最小更新距离<br>
locationOption.distanceFilter = -1;
///设置iOS端期望的定位精度
/// 可选值:<br>
/// <li>[DesiredAccuracy.Best] 最高精度</li>
/// <li>[DesiredAccuracy.BestForNavigation] 适用于导航场景的高精度 </li>
/// <li>[DesiredAccuracy.NearestTenMeters] 10米 </li>
/// <li>[DesiredAccuracy.Kilometer] 1000米</li>
/// <li>[DesiredAccuracy.ThreeKilometers] 3000米</li>
locationOption.desiredAccuracy = DesiredAccuracy.Best;
///设置iOS端是否允许系统暂停定位
locationOption.pausesLocationUpdatesAutomatically = false;
///将定位参数设置给定位插件
_locationPlugin.setLocationOption(locationOption);
}
}
///开始定位
void _startLocation() {
if (null != _locationPlugin) {
///开始定位之前设置定位参数
_setLocationOption();
_locationPlugin.startLocation();
}
}
/// 动态申请定位权限
void requestPermission() async {
// 申请权限
bool hasLocationPermission = await requestLocationPermission();
if (hasLocationPermission) {
print("定位权限申请通过");
} else {
print("定位权限申请不通过");
}
}
/// 申请定位权限 授予定位权限返回true, 否则返回false
Future<bool> requestLocationPermission() async {
//获取当前的权限
var status = await Permission.location.status;
if (status == PermissionStatus.granted) {
//已经授权
return true;
} else {
//未授权则发起一次申请
status = await Permission.location.request();
if (status == PermissionStatus.granted) {
return true;
} else {
return false;
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("地理定位演示"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// latitude: 36.570091461155336, longitude: 109.5080830206976
//
Text("纬度:$_latitude"),
Text("经度:$_longitude"),
const SizedBox(height: 20),
ElevatedButton(
child: const Text('开始定位'),
onPressed: () {
_startLocation();
},
),
],
),
),
);
}
}
5、支付宝支付
class _AlipayPagerState extends State<AlipayPager> {
_doAliPay() async {
Tobias tobias = Tobias();
var response = await Dio().get("https://agent.itying.com/alipay/");
var aliPayResult = await tobias.pay(response.data);
print(aliPayResult); //跳转到订单列表
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Title'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(onPressed: _doAliPay, child: const Text("支付宝支付"))
],
),
),
);
}
}
6、APP升级安装
class _AppVersionPageState extends State<AppVersionPage> {
@override
void initState() {
// TODO: implement initState
super.initState();
getPackageInfo();
getAppPath();
}
//弹出Dialog 备用
void showUpgradesDialog() async {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text("更新APP提示!"),
content: const Text("发现新的版本,新版本修复了如下bug 是否更新!"),
actions: <Widget>[
ElevatedButton(
child: const Text("否"),
onPressed: () {
Navigator.pop(context, 'Cancle');
},
),
ElevatedButton(
child: const Text("是"),
onPressed: () {
Navigator.pop(context, 'Ok');
},
)
],
);
});
}
//获取版本号
getPackageInfo() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String appName = packageInfo.appName;
String packageName = packageInfo.packageName;
String version = packageInfo.version; //1.0.0
String buildNumber = packageInfo.buildNumber; //1
}
//获取路径
getAppPath() async {
Directory? directory = await getExternalStorageDirectory();
// /storage/emulated/0/Android/data/com.example.flutter_demo/files
String storageDirectory = directory!.path;
}
//检查权限
Future<bool> checkPermission() async {
if (Theme.of(context).platform == TargetPlatform.android) {
final status = await Permission.storage.status;
if (status != PermissionStatus.granted) {
final result = await Permission.storage.request();
if (result == PermissionStatus.granted) {
return true;
}
} else {
return true;
}
}
return false;
}
//下载打开文件
downLoad() async {
var permission = await checkPermission();
if (permission) {
final directory = await getExternalStorageDirectory();
String localPath = directory!.path;
String appName = "aaa.apk";
String savePath = "$localPath/$appName";
String apkUrl = "https://jd.itying.com/jdshop.apk";
///参数一 文件的网络储存URL
///参数二 下载的本地目录文件
///参数三 下载监听
Dio dio = Dio();
await dio.download(apkUrl, savePath,
onReceiveProgress: (received, total) {
if (total != -1) {
///当前下载的百分比例
print((received / total * 100).toStringAsFixed(0) + "%");
}
});
print(savePath);
await OpenFilex.open(savePath,
type: "application/vnd.android.package-archive");
} else {
print("没有权限");
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: downLoad,
child: const Icon(Icons.arrow_downward),
),
appBar: AppBar(
title: const Text("app升级演示"),
),
body: const Text("app升级演示"),
);
}
}
7、微信 登录、分享、支付
class _WeixinPaySharePagerState extends State<WeixinPaySharePager> {
Fluwx fluwx = Fluwx();
String text = "share text from fluwx"; //分享的文字
// WeChatScene scene = WeChatScene.session; //分享给好友
WeChatScene scene = WeChatScene.timeline; //分享到朋友圈
@override
void initState() {
super.initState();
//初始化fluwx插件
fluwx.registerApi(
appId: "wx5881fa2638a2ca60",
//universalLink 只针对ios
universalLink: "https://www.itying.com/flutter/");
//监听微信支付返回的结果
fluwx.addSubscriber((response) {
if (response is WeChatPaymentResponse) {
setState(() {
print("pay :${response.isSuccessful}");
});
}
});
//监听微信登录
fluwx.addSubscriber((response) async {
if (response is WeChatAuthResponse) {
setState(() async {
print("state :${response.state} \n code:${response.code}");
var apiUrl =
'http://agent.itying.com/wxpay/getUserInfo.php?code=${response.code}';
var userinfo = await Dio().get(apiUrl);
Map result = json.decode(userinfo.data);
print(result);
});
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('WeixinPay'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
child: const Text('微信支付'),
onPressed: () async {
var apiUrl = 'http://agent.itying.com/wxpay/';
//链接自己服务器获取到data然后调用微信pay方法
var myPayInfo = await Dio().get(apiUrl);
Map<String, dynamic> result = json.decode(myPayInfo.data);
fluwx.pay(
which: Payment(
appId: result['appid'].toString(),
partnerId: result['partnerid'].toString(),
prepayId: result['prepayid'].toString(),
packageValue: result['package'].toString(),
nonceStr: result['noncestr'].toString(),
timestamp: result['timestamp'],
sign: result['sign'].toString(),
));
},
),
const SizedBox(height: 10),
ElevatedButton(
child: const Text('微信登录'),
onPressed: () {
fluwx
.authBy(
which: NormalAuth(
scope: 'snsapi_userinfo',
state: 'wechat_sdk_demo_test',
))
.then((data) {});
},
),
const SizedBox(height: 10),
ElevatedButton(
child: const Text('微信分享文字'),
onPressed: () {
fluwx.share(WeChatShareTextModel(text, scene: scene));
},
),
const SizedBox(height: 10),
ElevatedButton(
child: const Text('微信分享 图文信息'),
onPressed: () {
var model = WeChatShareWebPageModel(
"https://www.baidu.com",
title: "百度官网",
thumbnail: WeChatImage.network(
"https://www.itying.com/images/201906/goods_img/1120_P_1560842352183.png"),
scene: scene,
);
fluwx.share(model);
},
)
],
)));
}
}
网友评论