Flutter 第三方一些应用及打包

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);
              },
            )
          ],
        )));
  }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容