r_upgrade 0.3.1

  • Readme
  • Changelog
  • Example
  • Installing
  • 87

r_upgrade #

pub package

中文点此 #

Android and IOS upgrade plugin.

  • [✔] Jump link mode upgrade
  • [✔] Jump to store mode upgrade
  • [✔] Android Download APK using download link
    • [✔] Monitor download information
    • [✔] cancel/pause/continue download
    • [✔] Get download status according to ID
    • [✔] Install app according to ID
    • [✔] Get the last download ID (based on the version name and version number)
    • [✔] Modify the information displayed in the notification bar
  • [✔] Android hot upgrade
  • [✔] Android increment upgrade
  • [✔] IOS Jump to Appstore upgrade according to appid
  • [✔] IOS Get the current online version of Appstore according to appid

Getting Started #

1. Use Plugin: #

add this code in pubspec.yaml

dependencies:
  r_upgrade: last version

2. Upgrade from your website ( Android or IOS ) #

    void upgradeFromUrl()async{
        bool isSuccess =await RUpgrade.upgradeFromUrl(
                    'https://www.google.com',
                  );
        print(isSuccess);
    }

Android Platform #

1. App upgrade from store. #

    void upgradeFromAndroidStore(){
       bool isSuccess = await RUpgrade.upgradeFromAndroidStore(AndroidStore.GOOGLE_PLAY);
       print('${isSuccess?'jump success':'jump error'}');
    }

make sure your application had this permission and request dynamic permission.

    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

1. Add Upgrade Download Listener

RUpgrade.stream.listen((DownloadInfo info){
  ///...
});

info:

paramdesc
(int) iddownload id
(int) max_lengthdownload max bytes length (bytes)
(int) current_lengthdownload current bytes length (bytes)
(double) percentdownload percent 0-100
(double) planTimedownload plan time /s (X.toStringAsFixed(0))
(String) pathdownload file path
(double) speeddownload speed kb/s
(DownloadStatus) statusdownload status
STATUS_PAUSED
STATUS_PENDING
STATUS_RUNNING
STATUS_SUCCESSFUL
STATUS_FAILED
STATUS_CANCEL

2. Upgrade your application

This upgrade have two part. useDownloadManager:

  • true: Use system DownloadManagerto download
    • advantage:Simple, use system.
    • Inferiority:can not use http download , can not click the notification pause downloading, can not pause and continue download by network status etc...
    • support: RUpgrade.streaminstallcancel
  • false: Use Service download(default use)
    • advantage:Power, support http/https download, support auto pause and continue download by network status etc..
    • Inferiority:No bugs found yet. If you find a bug, you are welcome to issue
    • support: RUpgrade.streaminstallcancel
    // [isAutoRequestInstall] downloaded finish will auto request install apk.
    // [apkName] apk name (such as `release.apk`)
    // [notificationVisibility] notification visibility.
    // [notificationStyle] download notification show style about content text, only support [useDownloadManager]==false.
    // [useDownloadManager] if true will use DownloadManager,false will use my service ,
    //         if true will no use [pause] , [upgradeWithId] , [getDownloadStatus] , [getLastUpgradedId] methods.
    // [upgradeFlavor] you can use [RUpgradeFlavor.normal] , [RUpgradeFlavor.hotUpgrade] , [RUpgradeFlavor.incrementUpgrade] flavor
    void upgrade() async {
      int id = await RUpgrade.upgrade(
                 'https://raw.githubusercontent.com/rhymelph/r_upgrade/master/apk/app-release.apk',
                 apkName: 'app-release.apk',isAutoRequestInstall: true);
    }

New upgraded flavor:(no support use DownloadManager)

enum RUpgradeFlavor {
  normal, // full upgrade
  hotUpgrade, // hot upgrade
  incrementUpgrade, // increment upgrade
}

3. Cancel Download

    void cancel() async {
      bool isSuccess=await RUpgrade.cancel(id);
    }

4. Install Apk

    void install() async {
      bool isSuccess=await RUpgrade.install(id);
    }

5. Pause Download

    void pause() async {
      bool isSuccess=await RUpgrade.pause(id);
    }

6. Continue Download

    void pause() async {
      bool isSuccess=await RUpgrade.upgradeWithId(id);
      /// return true.
      /// * if download status is [STATUS_PAUSED] or [STATUS_FAILED] or [STATUS_CANCEL], will restart running.
      /// * if download status is [STATUS_RUNNING] or [STATUS_PENDING], nothing happened.
      /// * if download status is [STATUS_SUCCESSFUL] , will install apk.
      ///
      /// return false.
      /// * if not found the id , will return [false].
    }

7. Get the last upgrade id

    void getLastUpgradeId() async {
     int id = await RUpgrade.getLastUpgradedId();
    }

8. Get the download status from id

    void getDownloadStatus()async{
    DownloadStatus status = await RUpgrade.getDownloadStatus(id);
   }

9. Increment Upgrade

  • 1.Download bsdiff to local.
  • 2.Prepare two installation packages, one is the one to be upgraded( old.apk ), an installation package that you need to update( new.apk )
  • 3.Switch to the 'bsdiff' directory downloaded above on the command line, and run the command./bsdiff old.apk new.apk increment.patch
  • 4.Put theincrement.patchUpload to server
  • 5.use RUpgrade.upgrade(...,upgradeFlavor:RUpgradeFlavor.incrementUpgrade)download file
  • 6.use RUpgrade.install(id) install apk.

The code is as follows:

    int id;
    void incrementUpgrade(){
        id = await RUpgrade.upgrade(
                'https://mydata-1252536312.cos.ap-guangzhou.myqcloud.com/r_upgrade.patch',
                fileName: 'r_upgrade.patch',
                useDownloadManager: false,
                isAutoRequestInstall: false,
                upgradeFlavor: RUpgradeFlavor.incrementUpgrade,
              );
    }

    void install(){
        try {
            await RUpgrade.install(id);
        } catch (e) {
            _state.currentState
                .showSnackBar(SnackBar(content: Text('failure!')));
        }
    }

10. Hot Upgrade

  • you can use this id to hot upgrade,but download file is zip. include three file [isolate_snapshot_data]、[kernel_blob.bin]、[vm_snapshot_data].Your can use flutter build bundle generate.
 flutter build bundle
  • generate file path form ./build/flutter_assets and packaged into zip.
|- AssetManifest.json
|- FontManifest.json
|- fonts
    |- ...
|- isolate_snapshot_data *
|- kernel-blob.bin       *
|- LICENSE
|- packages
    |- ...
|- vm_snapshot_data      *
  • use RUpgrade.upgrade(...,upgradeFlavor:RUpgradeFlavor.hotUpgrade)download file.
  • download complete you can use download id to hot upgrade
           bool isSuccess = await RUpgrade.hotUpgrade(id);
           if (isSuccess) {
              _state.currentState
                    .showSnackBar(SnackBar(content: Text('Hot update succeeded, exit the application after 3S, please enter again')));
                Future.delayed(Duration(seconds: 3)).then((_){
                  SystemNavigator.pop(animated: true);
                });
           }else{
              _state.currentState
                    .showSnackBar(SnackBar(content: Text('Hot update failed, please wait for update package download to complete')));
              }

At present, the hot update is still in the testing stage, only supporting the change of the flutter code, not supporting the resource file, etc. the author of the plug-in is not responsible for all the consequences caused by the hot update, and the user is responsible for it.

Android Platform Notification Bar #

If you want to customize the content displayed in the download notification bar, you can do so, modify or add files project/android/app/main/res/r_upgrade_value.xml,add the following code

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="r_upgrade_download_speech">%.0f kb/s</string>
    <string name="r_upgrade_download_planTime">%.0fs left</string>
    <string name="r_upgrade_download_finish">Download finished</string>
    <string name="r_upgrade_download_paused">Download paused</string>
    <string name="r_upgrade_download_failed">Download failed</string>
</resources>

And then.When you use upgrade method,you should set the notificationStyle param.

/// Notification show style about content text
enum NotificationStyle {
  speechAndPlanTime, // 100kb/s 1s left
  planTimeAndSpeech, // 1s left 100kb/s
  speech,// 100kb/s
  planTime, // 1s left
  none, //
}

IOS Platform #

1.Go to the AppStore Upgrade #

    void upgradeFromAppStore() async {
        bool isSuccess =await RUpgrade.upgradeFromAppStore(
                 'your AppId',//such as:WeChat AppId:414478124
              );
        print(isSuccess);
    }

2.Get the last version form AppStore #

    void getVersionFromAppStore() async {
        String versionName = await RUpgrade.getVersionFromAppStore(
                'your AppId',//such as:WeChat AppId:414478124
               );
        print(versionName);
    }

0.3.1 #

  • add Android permission check, when you use upgrade or install.

0.3.0 #

  • remove hotUpgrade method,add increment upgrade.edit upgrade method.

0.2.6 #

  • fix mini bug ,and change notification channel name ,fix example hot upgrade error.

0.2.5 #

  • add notificationStyle params from upgrade method.

0.2.4 #

  • add upgradeFromAndroidStore method.

0.2.2 #

  • fix not use stream can not open notification,update upgradeWithId method.

0.2.1 #

  • fix Android 6.0 install error.

0.2.0 #

  • will power and awesome .

0.1.8 #

  • adapter FlutterPlugin .

0.1.7 #

  • add hot upgrade.

0.1.6 #

  • fix file provider merge error and add can select auto apk install.

0.1.5 #

  • add license.

0.1.4 #

0.1.3 #

  • fix progress will decrement.

0.1.2 #

  • fix progress is null and speed is negative issus.

0.1.1 #

  • add ios upgrade from AppStore.

0.1.0 #

  • fix install apk.

0.0.2 #

  • Improving health.

0.0.1 #

  • release plugin.

example/lib/main.dart

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';

//import 'package:permission_handler/permission_handler.dart';
import 'package:r_upgrade/r_upgrade.dart';

const version = 1;

void main() => runApp(MyApp());

enum UpgradeMethod {
  all,
  hot,
  increment,
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int id;
  bool isAutoRequestInstall = false;

  UpgradeMethod upgradeMethod;

  GlobalKey<ScaffoldState> _state = GlobalKey();

  String iosVersion = "";

  @override
  void initState() {
    super.initState();
    RUpgrade.setDebug(true);
  }

  Widget _buildMultiPlatformWidget() {
    if (Platform.isAndroid) {
      return _buildAndroidPlatformWidget();
    } else if (Platform.isIOS) {
      return _buildIOSPlatformWidget();
    } else {
      return Container(
        child: Text('Sorry, your platform is not support'),
      );
    }
  }

  Widget _buildIOSPlatformWidget() => ListView(
        children: <Widget>[
          ListTile(
            title: Text('Go to url(WeChat)'),
            onTap: () async {
              RUpgrade.upgradeFromUrl(
                'https://apps.apple.com/cn/app/wechat/id414478124?l=en',
              );
            },
          ),
          ListTile(
            title: Text('Go to appStore from appId(WeChat)'),
            onTap: () async {
              RUpgrade.upgradeFromAppStore(
                '414478124',
              );
            },
          ),
          ListTile(
            title: Text('get version from app store(WeChat)'),
            trailing: iosVersion != null
                ? Text(iosVersion,
                    style: Theme.of(context).textTheme.subtitle2.copyWith(
                          color: Colors.grey,
                        ))
                : null,
            onTap: () async {
              String versionName =
                  await RUpgrade.getVersionFromAppStore('414478124');
              setState(() {
                iosVersion = versionName;
              });
            },
          ),
        ],
      );

  Widget _buildAndroidPlatformWidget() => ListView(
        children: <Widget>[
          _buildDownloadWindow(),
          Divider(),
          ListTile(
            title: Text(
              '更新相关',
              style: Theme.of(context).textTheme.title.copyWith(
                    fontWeight: FontWeight.w600,
                  ),
            ),
          ),
          ListTile(
            title: Text('跳转到应用商店'),
            onTap: () async {
              bool isSuccess =
                  await RUpgrade.upgradeFromAndroidStore(AndroidStore.BAIDU);
              print('${isSuccess ? '跳转成功' : '跳转失败'}');
            },
          ),
          ListTile(
            title: Text('跳转到链接更新'),
            onTap: () async {
              bool isSuccess = await RUpgrade.upgradeFromUrl(
                'https://www.baidu.com',
              );
              print(isSuccess);
            },
          ),
          ListTile(
            title: Text('开始全量更新'),
            onTap: () async {
              if (upgradeMethod != null) {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text(getUpgradeMethod())));
                return;
              }

//              if (!await canReadStorage()) return;
              id = await RUpgrade.upgrade(
//                "http://192.168.1.105:8888/files/static/kuan.apk",
//                  'http://dl-cdn.coolapkmarket.com/down/apk_file/2020/0308/Coolapk-v10.0.3-2003081-coolapk-app-release.apk?_upt=b210caeb1585012557',
                  'https://mydata-1252536312.cos.ap-guangzhou.myqcloud.com/r_upgrade.apk',
                  fileName: 'r_upgrade.apk',
                  isAutoRequestInstall: isAutoRequestInstall,
                  notificationStyle: NotificationStyle.speechAndPlanTime,
                  useDownloadManager: false);
              upgradeMethod = UpgradeMethod.all;
              setState(() {});
            },
          ),
          ListTile(
            title: Text('安装全量更新'),
            onTap: () async {
              if (upgradeMethod != UpgradeMethod.all && upgradeMethod != null) {
                _state.currentState.showSnackBar(
                    SnackBar(content: Text('请进行${getUpgradeMethodName()}')));
                return;
              }
              if (id == null) {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text('当前没有ID可安装')));
                return;
              }
              final status = await RUpgrade.getDownloadStatus(id);

              if (status == DownloadStatus.STATUS_SUCCESSFUL) {
                bool isSuccess = await RUpgrade.install(id);
                if (isSuccess) {
                  _state.currentState
                      .showSnackBar(SnackBar(content: Text('请求成功')));
                }
              } else {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text('当前ID未完成下载')));
              }
            },
          ),
          CheckboxListTile(
            value: isAutoRequestInstall,
            onChanged: (bool value) {
              setState(() {
                isAutoRequestInstall = value;
              });
            },
            title: Text('下载完进行安装'),
          ),
          ListTile(
            title: Text('继续更新'),
            onTap: () async {
              if (id == null) {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text('当前没有ID可升级')));
                return;
              }
              if (upgradeMethod != null) {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text(getUpgradeMethod())));
                return;
              }
              await RUpgrade.upgradeWithId(id);
              setState(() {});
            },
          ),
          ListTile(
            title: Text('暂停更新'),
            onTap: () async {
              bool isSuccess = await RUpgrade.pause(id);
              if (isSuccess) {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text('暂停成功')));
                setState(() {});
              }
              print('cancel');
            },
          ),
          ListTile(
            title: Text('取消更新'),
            onTap: () async {
              bool isSuccess = await RUpgrade.cancel(id);
              if (isSuccess) {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text('取消成功')));
                id = null;
                upgradeMethod = null;
                setState(() {});
              }
              print('cancel');
            },
          ),
          Divider(),
          ListTile(
            title: Text(
              '热更新相关',
              style: Theme.of(context).textTheme.title.copyWith(
                    fontWeight: FontWeight.w600,
                  ),
            ),
          ),
          ListTile(
            title: Text('开始下载热更新'),
            onTap: () async {
              if (upgradeMethod != null) {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text(getUpgradeMethod())));
                return;
              }
//              if (!await canReadStorage()) return;
              id = await RUpgrade.upgrade(
                  'https://mydata-1252536312.cos.ap-guangzhou.myqcloud.com/r_upgrade.zip',
                  fileName: 'r_upgrade.zip',
                  useDownloadManager: false,
                  isAutoRequestInstall: false,
                  upgradeFlavor: RUpgradeFlavor.hotUpgrade);
              upgradeMethod = UpgradeMethod.hot;
              setState(() {});
            },
          ),
          ListTile(
            title: Text('进行热更新'),
            onTap: () async {
//              if (!await canReadStorage()) return;
              if (upgradeMethod != UpgradeMethod.hot && upgradeMethod != null) {
                _state.currentState.showSnackBar(
                    SnackBar(content: Text('请进行${getUpgradeMethodName()}')));
                return;
              }
              if (id == null) {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text('请点击开始热更新')));
                return;
              }
//              bool isSuccess = await RUpgrade.hotUpgrade(id);
              final status = await RUpgrade.getDownloadStatus(id);

              if (status == DownloadStatus.STATUS_SUCCESSFUL) {
                bool isSuccess = await RUpgrade.install(id);
                if (isSuccess) {
                  _state.currentState.showSnackBar(
                      SnackBar(content: Text('热更新成功,3s后退出应用,请重新进入')));
                  Future.delayed(Duration(seconds: 3)).then((_) {
                    SystemNavigator.pop(animated: true);
                  });
                } else {
                  _state.currentState.showSnackBar(
                      SnackBar(content: Text('热更新失败,请等待更新包下载完成')));
                }
              } else {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text('当前ID未完成下载')));
              }
            },
          ),
          Divider(),
          ListTile(
            title: Text(
              '增量更新',
              style: Theme.of(context).textTheme.title.copyWith(
                    fontWeight: FontWeight.w600,
                  ),
            ),
          ),
          ListTile(
            title: Text('开始下载增量更新'),
            onTap: () async {
              if (upgradeMethod != null) {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text(getUpgradeMethod())));
                return;
              }
//              if (!await canReadStorage()) return;
              id = await RUpgrade.upgrade(
                'https://mydata-1252536312.cos.ap-guangzhou.myqcloud.com/r_upgrade.patch',
                fileName: 'r_upgrade.patch',
                useDownloadManager: false,
                isAutoRequestInstall: false,
                upgradeFlavor: RUpgradeFlavor.incrementUpgrade,
              );
              upgradeMethod = UpgradeMethod.increment;
              setState(() {});
            },
          ),
          ListTile(
            title: Text('进行增量更新'),
            onTap: () async {
//              if (!await canReadStorage()) return;
              if (upgradeMethod != UpgradeMethod.increment &&
                  upgradeMethod != null) {
                _state.currentState.showSnackBar(
                    SnackBar(content: Text('请进行${getUpgradeMethodName()}}')));
                return;
              }
              if (id == null) {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text('请点击开始增量更新')));
                return;
              }
              try {
                final status = await RUpgrade.getDownloadStatus(id);
                if (status == DownloadStatus.STATUS_SUCCESSFUL) {
                  await RUpgrade.install(id);
                } else {
                  _state.currentState
                      .showSnackBar(SnackBar(content: Text('当前ID未完成下载')));
                }
              } catch (e) {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text('增量更新失败!')));
              }
            },
          ),
          Divider(),
          ListTile(
            title: Text(
              '历史相关',
              style: Theme.of(context).textTheme.title.copyWith(
                    fontWeight: FontWeight.w600,
                  ),
            ),
          ),
          ListTile(
            title: Text('获取最后一次下载的ID'),
            trailing: lastId != null
                ? Text(
                    lastId.toString(),
                    style: Theme.of(context).textTheme.subtitle2.copyWith(
                          color: Colors.grey,
                        ),
                  )
                : null,
            onTap: () async {
              lastId = await RUpgrade.getLastUpgradedId();
              if (lastId == null) {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text('没有最后一次下载的ID')));
                return;
              }
              setState(() {});
            },
          ),
          ListTile(
            title: Text('根据最后一次ID升级应用'),
            onTap: () async {
              if (lastId == null) {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text('当前没有ID可升级')));
                return;
              }
              await RUpgrade.upgradeWithId(lastId);
              setState(() {});
            },
          ),
          ListTile(
            title: Text(
              '查看最后一次ID的下载状态',
            ),
            trailing: lastStatus != null
                ? Text(getStatus(lastStatus),
                    style: Theme.of(context).textTheme.subtitle2.copyWith(
                          color: Colors.grey,
                        ))
                : null,
            onTap: () async {
              if (lastId == null) {
                _state.currentState
                    .showSnackBar(SnackBar(content: Text('当前没有ID可查')));
                return;
              }
              lastStatus = await RUpgrade.getDownloadStatus(lastId);
              setState(() {});
            },
          ),
          Divider(),
        ],
      );

  int lastId;

  DownloadStatus lastStatus;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        key: _state,
        appBar: AppBar(
          backgroundColor: getVersionColor(),
          title: Text(_getAppBarText()),
        ),
        body: _buildMultiPlatformWidget(),
      ),
    );
  }

  Color getVersionColor() {
    switch (version) {
      case 1:
        return Theme.of(context).primaryColor;
      case 2:
        return Colors.black;
      case 3:
        return Colors.red;
      case 4:
        return Colors.orange;
    }
    return Theme.of(context).primaryColor;
  }

  String _getAppBarText() {
    switch (version) {
      case 1:
        return 'Normal version = $version ${id != null ? 'id = $id' : ''}';
      case 2:
        return 'hot upgrade version = $version ${id != null ? 'id = $id' : ''}';
      case 3:
        return 'all upgrade version = $version ${id != null ? 'id = $id' : ''}';
      case 4:
        return 'plus upgrade version = $version ${id != null ? 'id = $id' : ''}';
    }
    return 'unknow version  = $version ${id != null ? 'id = $id' : ''}';
  }

  Widget _buildDownloadWindow() => Container(
        height: 250,
        alignment: Alignment.center,
        padding: EdgeInsets.symmetric(horizontal: 16),
        decoration: BoxDecoration(
          color: Colors.grey[200],
        ),
        child: id != null
            ? StreamBuilder(
                stream: RUpgrade.stream,
                builder: (BuildContext context,
                    AsyncSnapshot<DownloadInfo> snapshot) {
                  if (snapshot.hasData) {
                    return Column(
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        SizedBox(
                          height: 150,
                          width: 150,
                          child: CircleDownloadWidget(
                            backgroundColor: snapshot.data.status ==
                                    DownloadStatus.STATUS_SUCCESSFUL
                                ? Colors.green
                                : null,
                            progress: snapshot.data.percent / 100,
                            child: Center(
                              child: Text(
                                snapshot.data.status ==
                                        DownloadStatus.STATUS_RUNNING
                                    ? getSpeech(snapshot.data.speed)
                                    : getStatus(snapshot.data.status),
                                style: TextStyle(
                                  color: Colors.white,
                                ),
                              ),
                            ),
                          ),
                        ),
                        SizedBox(
                          height: 30,
                        ),
                        Text(
                            '${snapshot.data.planTime.toStringAsFixed(0)}s后完成'),
                      ],
                    );
                  } else {
                    return SizedBox(
                      width: 60,
                      height: 60,
                      child: CircularProgressIndicator(
                        strokeWidth: 2,
                      ),
                    );
                  }
                },
              )
            : Text('等待下载'),
      );

  String getStatus(DownloadStatus status) {
    if (status == DownloadStatus.STATUS_FAILED) {
      id = null;
      upgradeMethod = null;
      return "下载失败";
    } else if (status == DownloadStatus.STATUS_PAUSED) {
      return "下载暂停";
    } else if (status == DownloadStatus.STATUS_PENDING) {
      return "获取资源中";
    } else if (status == DownloadStatus.STATUS_RUNNING) {
      return "下载中";
    } else if (status == DownloadStatus.STATUS_SUCCESSFUL) {
      return "下载成功";
    } else if (status == DownloadStatus.STATUS_CANCEL) {
      id = null;
      upgradeMethod = null;
      return "下载取消";
    } else {
      id = null;
      upgradeMethod = null;
      return "未知";
    }
  }

  String getUpgradeMethod() {
    switch (upgradeMethod) {
      case UpgradeMethod.all:
        return '已经开始全量更新';
        break;
      case UpgradeMethod.hot:
        return '已经开始热更新';
        break;
      case UpgradeMethod.increment:
        return '已经开始增量更新';
        break;
    }
    return '';
  }

  String getUpgradeMethodName() {
    switch (upgradeMethod) {
      case UpgradeMethod.all:
        return '全量更新';
        break;
      case UpgradeMethod.hot:
        return '热更新';
        break;
      case UpgradeMethod.increment:
        return '增量更新';
        break;
    }
    return '';
  }
//  Future<bool> canReadStorage() async {
//    if (Platform.isIOS) return true;
//    var status = await PermissionHandler()
//        .checkPermissionStatus(PermissionGroup.storage);
//    if (status != PermissionStatus.granted) {
//      var future = await PermissionHandler()
//          .requestPermissions([PermissionGroup.storage]);
//      for (final item in future.entries) {
//        if (item.value != PermissionStatus.granted) {
//          return false;
//        }
//      }
//    } else {
//      return true;
//    }
//    return true;
//  }

  String getSpeech(double speech) {
    String unit = 'kb/s';
    String result = speech.toStringAsFixed(2);
    if (speech > 1024 * 1024) {
      unit = 'gb/s';
      result = (speech / (1024 * 1024)).toStringAsFixed(2);
    } else if (speech > 1024) {
      unit = 'mb/s';
      result = (speech / 1024).toStringAsFixed(2);
    }
    return '$result$unit';
  }
}

class CircleDownloadWidget extends StatelessWidget {
  final double progress;
  final Widget child;
  final Color backgroundColor;

  const CircleDownloadWidget(
      {Key key, this.progress, this.child, this.backgroundColor})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return RepaintBoundary(
      child: CustomPaint(
        painter: CircleDownloadCustomPainter(
          backgroundColor ?? Colors.grey[400],
          Theme.of(context).primaryColor,
          progress,
        ),
        child: child,
      ),
    );
  }
}

class CircleDownloadCustomPainter extends CustomPainter {
  final Color backgroundColor;
  final Color color;
  final double progress;

  Paint mPaint;

  CircleDownloadCustomPainter(this.backgroundColor, this.color, this.progress);

  @override
  void paint(Canvas canvas, Size size) {
    if (mPaint == null) mPaint = Paint();
    double width = size.width;
    double height = size.height;

    Rect progressRect =
        Rect.fromLTRB(0, height * (1 - progress), width, height);
    Rect widgetRect = Rect.fromLTWH(0, 0, width, height);
    canvas.clipPath(Path()..addOval(widgetRect));

    canvas.drawRect(widgetRect, mPaint..color = backgroundColor);
    canvas.drawRect(progressRect, mPaint..color = color);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  r_upgrade: ^0.3.1

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:r_upgrade/r_upgrade.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
74
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
87
Learn more about scoring.

We analyzed this package on Jul 2, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.4
  • pana: 0.13.13
  • Flutter: 1.17.5

Analysis suggestions

Package does not support Flutter platform linux

Because of import path [package:r_upgrade/r_upgrade.dart] that declares support for platforms: android, ios

Package does not support Flutter platform macos

Because of import path [package:r_upgrade/r_upgrade.dart] that declares support for platforms: android, ios

Package does not support Flutter platform web

Because of import path [package:r_upgrade/r_upgrade.dart] that declares support for platforms: android, ios

Package does not support Flutter platform windows

Because of import path [package:r_upgrade/r_upgrade.dart] that declares support for platforms: android, ios

Package not compatible with SDK dart

because of import path [r_upgrade] that is in a package requiring null.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.12 1.14.13
meta 1.1.8
sky_engine 0.0.99
typed_data 1.1.6 1.2.0
vector_math 2.0.8
Dev dependencies
flutter_test