YSVersionView.dart 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import 'dart:io';
  2. import 'package:dio/dio.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter_wallet/tools/YSColors.dart';
  5. import 'package:open_file/open_file.dart';
  6. import 'package:package_info_plus/package_info_plus.dart';
  7. import 'package:path_provider/path_provider.dart';
  8. import 'package:permission_handler/permission_handler.dart';
  9. import 'package:webview_flutter/webview_flutter.dart';
  10. // import 'package:url_launcher/url_launcher_string.dart';
  11. import 'YSTools.dart';
  12. class YSVersionView extends StatefulWidget {
  13. final String content;
  14. final String url;
  15. final String title;
  16. final bool isBack;
  17. const YSVersionView({Key? key, required this.content, required this.url, required this.title, this.isBack = true}) : super(key: key);
  18. @override
  19. YSVersionViewState createState() => YSVersionViewState();
  20. }
  21. class YSVersionViewState extends State<YSVersionView> {
  22. int _progress = 0;
  23. bool _isTap = false;
  24. final WebViewController _webViewController = WebViewController();
  25. @override
  26. void initState() {
  27. _webViewController.loadHtmlString('''
  28. <!DOCTYPE html>
  29. <html lang="en">
  30. <meta name="viewport" content="width=device-width, initial-scale=1">
  31. <body>
  32. ${widget.content}
  33. </body>
  34. </html>
  35. ''');
  36. super.initState();
  37. }
  38. @override
  39. Widget build(BuildContext context) {
  40. return WillPopScope(
  41. onWillPop: () async{
  42. return widget.isBack;
  43. },
  44. child: Center(child: Container(
  45. height: hsp(330),
  46. width: ysWidth(context)-hsp(100),
  47. decoration: BoxDecoration(
  48. color: YSColors.containColor(context),
  49. borderRadius: const BorderRadius.all(Radius.circular(5))
  50. ),
  51. padding: EdgeInsets.all(hsp(10)),
  52. child: Column(
  53. children: [
  54. Container(
  55. height: hsp(30),
  56. alignment: Alignment.center,
  57. child: centerAlertText(widget.title, size: 18,
  58. color: YSColors.iconColor(context),line: 100),
  59. ),
  60. Container(
  61. height: hsp(230),
  62. alignment: Alignment.topLeft,
  63. padding: const EdgeInsets.only(bottom: 10),
  64. child: WebViewWidget(
  65. controller: _webViewController,
  66. )
  67. // SingleChildScrollView(
  68. // padding: EdgeInsets.all(hsp(5)),
  69. // child: centerAlertText(widget.content, size: 15,
  70. // color: YSColors.iconColor(context),line: 100),
  71. // ),
  72. ),
  73. GestureDetector(
  74. onTap: () async{
  75. if(_isTap)return;
  76. if(Platform.isAndroid==true){
  77. bool isPer = await _checkPermission();
  78. if(isPer==true){
  79. _isTap = true;
  80. _installApk(widget.url);
  81. }
  82. }else if(Platform.isIOS==true){
  83. // launchUrlString(widget.url);
  84. }
  85. },
  86. behavior: HitTestBehavior.opaque,
  87. child: Container(
  88. height: hsp(40),
  89. margin: EdgeInsets.only(left: hsp(20),right: hsp(20)),
  90. decoration: const BoxDecoration(
  91. color: Color(0xFF146DFE),
  92. borderRadius: BorderRadius.all(Radius.circular(3))
  93. ),
  94. alignment: Alignment.center,
  95. child: centerAlertText('立即升级${_progress==0||_progress==100?'':' $_progress%'}',
  96. color: Colors.white, size: 15,),
  97. ),
  98. ),
  99. ],
  100. ),
  101. )),
  102. );
  103. }
  104. Future<bool> _checkPermission() async {
  105. if(Platform.isAndroid==true){
  106. if (await Permission.requestInstallPackages.request().isDenied) {
  107. Map<Permission, PermissionStatus> statuses = await [
  108. Permission.requestInstallPackages,
  109. ].request();
  110. if(statuses[Permission.requestInstallPackages]!.isDenied){
  111. return false;
  112. }
  113. }
  114. }
  115. return true;
  116. }
  117. Future<File?> _downloadAndroid(String url) async {
  118. PackageInfo packageInfo = await PackageInfo.fromPlatform();
  119. /// 创建存储文件
  120. Directory? storageDir = await getExternalStorageDirectory();
  121. String storagePath = storageDir!.path;
  122. File file = File('$storagePath/${packageInfo.appName}v'
  123. '${packageInfo.buildNumber}.apk');
  124. if (!file.existsSync()) {
  125. file.createSync();
  126. }
  127. try {
  128. /// 发起下载请求
  129. Response response = await Dio().get(url,
  130. onReceiveProgress: showDownloadProgress,
  131. options: Options(responseType: ResponseType.bytes,followRedirects: false,
  132. ));
  133. file.writeAsBytesSync(response.data);
  134. return file;
  135. } catch (e) {
  136. return null;
  137. }
  138. }
  139. /// 安装apk
  140. Future<void> _installApk(String url) async {
  141. File? apkFile = await _downloadAndroid(url);
  142. String apkFilePath = apkFile!.path;
  143. if (apkFilePath.isEmpty) {
  144. return;
  145. }
  146. OpenFile.open(apkFilePath);
  147. }
  148. /// 展示下载进度
  149. void showDownloadProgress(num received, num total) {
  150. if (total != -1) {
  151. _progress = int.parse('${(received / total~/0.01)}');
  152. setState(() {});
  153. if(_progress==100){
  154. _isTap = false;
  155. }
  156. }
  157. }
  158. }
  159. centerAlertText(String text,{Color color = Colors.white,required int size,bool isBold = false,int line = 1}) {
  160. return Text(text,style: TextStyle(fontSize: zsp(size),color: color,decoration: TextDecoration.none,
  161. fontWeight: isBold?FontWeight.bold:FontWeight.normal,),maxLines: line,overflow: TextOverflow.ellipsis,);
  162. }