1、Flutter 報錯 Could not create task ‘xxx‘.this and base files have different roots
1、問題場景:此問題會出現(xiàn)在你的項目路徑不在 C 盤(系統(tǒng)盤)或是不在 flutter sdk 所在盤符下。正常在 flutter 項目中運行沒有問題,會出現(xiàn)在將 flutter 以 Android 項目打開。
看報錯信息,屬于是文件存在在了兩個路徑,它不知道咋整。可能是編譯Android 項目時,默認會將第三方的緩存在系統(tǒng)盤。
2、解決辦法:
方法一、把項目復(fù)制到和 flutter 相同的目錄下,重新打開項目即可
方法二、a、在項目盤符下新建文件夾,正常命名(別整中文和特殊符號,flutter_pub_cache我覺得就不錯),然后打開環(huán)境變量,新建或編輯系統(tǒng)環(huán)境變量,輸入PUB_CACHE,然后將你剛才創(chuàng)建的文件路徑填進去。
b、重啟電腦
c、打開flutter 項目,flutter pub get,
d、打開 Android 項目,本次編譯可能時間較長
原文鏈接:https://blog.csdn.net/LoveShadowing/article/details/132210526
2、shared_preferences
本地存儲工具類,不限制string bool int list及l(fā)ist<Map>等結(jié)構(gòu)
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('保存數(shù)據(jù)'),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: _getData,
child: const Text('獲取數(shù)據(jù)'),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: _removeData,
child: const Text('清除數(shù)據(jù)'),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
Storage.setData("username", "李四");
},
child: const Text("設(shè)置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("設(shè)置List")),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
var list = await Storage.getData("newslist");
},
child: const Text("獲取List數(shù)據(jù)")),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
Storage.setData("num", 123.4);
},
child: const Text("設(shè)置num數(shù)據(jù)")),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
var num = await Storage.getData("num");
},
child: const Text("獲取num數(shù)據(jù)")),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
Storage.setData("flag", false);
},
child: const Text("設(shè)置bool數(shù)據(jù)")),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
var flag = await Storage.getData("flag");
},
child: const Text("獲取bool數(shù)據(jù)")),
],
),
),
);
}
}
3、barcode_scan2可以實現(xiàn)掃描條形碼、二維碼
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 = "內(nèi)容";
void doBarcodeScan() async {
var options = const ScanOptions(
// set the options
autoEnableFlash: true,
strings: {
'cancel': '取消',
'flash_on': '打開Flash',
'flash_off': '關(guān)閉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、地圖定位實現(xiàn)
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 = ""; //經(jīng)度
//監(jiān)聽定位
late StreamSubscription<Map<String, Object>> _locationListener;
//實例化插件
final AMapFlutterLocation _locationPlugin = AMapFlutterLocation();
@override
void initState() {
super.initState();
/// 動態(tài)申請定位權(quán)限
requestPermission();
AMapFlutterLocation.setApiKey(
"d21b99823c36665d5a2c1a06ee4a8186", "ios ApiKey");
///注冊定位結(jié)果監(jiān)聽
_locationListener = _locationPlugin
.onLocationChanged()
.listen((Map<String, Object> result) {
setState(() {
print(result);
_latitude = result["latitude"].toString();
_longitude = result["longitude"].toString();
});
});
}
@override
void dispose() {
super.dispose();
///移除定位監(jiān)聽
if (null != _locationListener) {
_locationListener.cancel();
}
///銷毀定位
if (null != _locationPlugin) {
_locationPlugin.destroy();
}
}
///設(shè)置定位參數(shù)
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";
///設(shè)置Android端連續(xù)定位的定位間隔
locationOption.locationInterval = 2000;
///設(shè)置Android端的定位模式<br>
///可選值:<br>
///<li>[AMapLocationMode.Battery_Saving]</li>
///<li>[AMapLocationMode.Device_Sensors]</li>
///<li>[AMapLocationMode.Hight_Accuracy]</li>
locationOption.locationMode = AMapLocationMode.Hight_Accuracy;
///設(shè)置iOS端的定位最小更新距離<br>
locationOption.distanceFilter = -1;
///設(shè)置iOS端期望的定位精度
/// 可選值:<br>
/// <li>[DesiredAccuracy.Best] 最高精度</li>
/// <li>[DesiredAccuracy.BestForNavigation] 適用于導(dǎo)航場景的高精度 </li>
/// <li>[DesiredAccuracy.NearestTenMeters] 10米 </li>
/// <li>[DesiredAccuracy.Kilometer] 1000米</li>
/// <li>[DesiredAccuracy.ThreeKilometers] 3000米</li>
locationOption.desiredAccuracy = DesiredAccuracy.Best;
///設(shè)置iOS端是否允許系統(tǒng)暫停定位
locationOption.pausesLocationUpdatesAutomatically = false;
///將定位參數(shù)設(shè)置給定位插件
_locationPlugin.setLocationOption(locationOption);
}
}
///開始定位
void _startLocation() {
if (null != _locationPlugin) {
///開始定位之前設(shè)置定位參數(shù)
_setLocationOption();
_locationPlugin.startLocation();
}
}
/// 動態(tài)申請定位權(quán)限
void requestPermission() async {
// 申請權(quán)限
bool hasLocationPermission = await requestLocationPermission();
if (hasLocationPermission) {
print("定位權(quán)限申請通過");
} else {
print("定位權(quán)限申請不通過");
}
}
/// 申請定位權(quán)限 授予定位權(quán)限返回true, 否則返回false
Future<bool> requestLocationPermission() async {
//獲取當前的權(quán)限
var status = await Permission.location.status;
if (status == PermissionStatus.granted) {
//已經(jīng)授權(quán)
return true;
} else {
//未授權(quán)則發(fā)起一次申請
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("經(jīng)度:$_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); //跳轉(zhuǎn)到訂單列表
}
@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("發(fā)現(xiàn)新的版本,新版本修復(fù)了如下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;
}
//檢查權(quán)限
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";
///參數(shù)一 文件的網(wǎng)絡(luò)儲存URL
///參數(shù)二 下載的本地目錄文件
///參數(shù)三 下載監(jiān)聽
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("沒有權(quán)限");
}
}
@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/");
//監(jiān)聽微信支付返回的結(jié)果
fluwx.addSubscriber((response) {
if (response is WeChatPaymentResponse) {
setState(() {
print("pay :${response.isSuccessful}");
});
}
});
//監(jiān)聽微信登錄
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/';
//鏈接自己服務(wù)器獲取到data然后調(diào)用微信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: "百度官網(wǎng)",
thumbnail: WeChatImage.network(
"https://www.itying.com/images/201906/goods_img/1120_P_1560842352183.png"),
scene: scene,
);
fluwx.share(model);
},
)
],
)));
}
}