Flutter 開発の実践 - アプリケーションの更新 APK のダウンロード、APK のインストール、アプリケーションの実装の開始

Flutter 開発の実践 - アプリケーションの更新 APK のダウンロード、APK のインストール、アプリケーションの実装の開始

開発プロセスでは、apk ファイルの新しいバージョンを更新してダウンロードし、次にアプリケーション更新 apk をダウンロードし、apk をインストールして、アプリケーションを起動する必要が頻繁に発生します。Flutter プロジェクトで APK をダウンロードし、現在のバージョンと更新してインストールする必要があるバージョンを比較し、VersionCode を判断して新しいバージョンの APK のダウンロードを決定します。

1.アプリケーションアップデートapkダウンロード

アプリケーションを更新する必要がある場合、バージョン番号を決定する必要がありますが、flutter プロジェクトでは、versionCode はプロジェクト内の pubspec.yaml のバージョンによって決まります。

たとえば、バージョン: 1.0.0+1

バージョンは 1.0.0、versionCode は 1

インターフェイスを取得する必要があります。判断する必要があるのは、apk をダウンロードする必要があるかどうかを判断する versionCode です。

1.1. 新しいバージョンのアドレスインターフェイスを取得する

新しいバージョンを取得するためのインターフェイスは、Dio ライブラリを使用します。dio は、グローバル設定、Restful API、FormData、インターセプター、リクエストのキャンセル、Cookie 管理、ファイルのアップロード/ダウンロード、タイムアウト、カスタム アダプターなどをサポートする強力な Dart HTTP リクエスト ライブラリです。

ここでのリクエストは GET リクエストです。

Response? response = await dio.get(requestUrl,
                  queryParameters: params,
                  options: Options(contentType: Headers.jsonContentType));

リクエストのロジックはここでは書きません。
リクエストに応じて入手したのは、

// チェックしたバージョンを取得する

Future<void> checkVersion() async {
    
    
    var params = {
    
    };

    ApiRepository.checkVersion(
        params: params,
        success: (response) {
    
    
          // {"version":"2","url":"http://wwww.laileshuo.com/download/myapp_v1.0.0_release.apk"}
          var object = response.object;
          if (object != null && (object is Map) && object.isNotEmpty) {
    
    
            String? versionCode = object['versionCode'];
            String? url = object['url'];
            // 判断是否需要下载更新
            String versionCodeStr = "";
            if (version != null) {
    
    
              versionCodeStr = "${
      
      versionCode}";
            }
            checkAppVersionUpdate(versionCodeStr: versionCodeStr, apkUrl: url);
          }
          print(
              "checkVersion params:${
      
      params}, object:${
      
      object.toString()}");
        },
        failure: (error) {
    
    
          print(
              "checkVersion params:${
      
      params}, error:${
      
      error.toString()}");
        });
  }

URL と versionCode は新しいバージョンのインターフェイスを確認することで取得され、ここでの versionCode を pubspec.yaml と比較して、apk をダウンロードする必要があるかどうかを確認します。

ダウンロード APK を決定する

Future<void> checkAppVersionUpdate({
    
    String? versionCodeStr, String? apkUrl}) async {
    
    
    try {
    
    
      if (versionCodeStr != null &&
          apkUrl != null &&
          versionCodeStr.isNotEmpty &&
          apkUrl.isNotEmpty) {
    
    
        String curVersionCodeStr = await PlatformUtils.getBuildNum();
        int versionCode = int.parse(versionCodeStr);
        int curVersionCode = int.parse(curVersionCodeStr);
        if (versionCode > curVersionCode) {
    
    
          // 需要更新的版本code,大于当前的版本才更新
          
        }
      }
    } catch (e) {
    
    
      print(
          "appVersionUpdate apkUrl:${
      
      apkUrl}, version:${
      
      version}, exception:${
      
      e.toString()}");
    }
  }

1.2. APKをダウンロードする

アップデートが必要と判断した場合は、新しいバージョンのapkをダウンロードする必要があります。ダウンロードしたライブラリにもDioを使用しています。

ダウンロードしたコードは、 https://blog.csdn.net/gloryFlow/article/details/131658621にあります。

新しいバージョンのダウンロードアドレスURLを取得したら、APKをダウンロードする必要があります

void downApk(String url, String saveDestPath) {
    
    
	HttpApi().doDownload(url, saveDestPath, cancelToken: CancelToken(),
        progress: (int received, int total) {
    
    
      // 下载进度
      setState(() {
    
    
        _downloadRatio = (received / total);
        if (_downloadRatio == 1) {
    
    
          _downloading = false;
        }
        _downloadIndicator = (_downloadRatio * 100).toStringAsFixed(2) + '%';
      });
    }, completion: () {
    
    
      // 下载成功
      FlutterLoadingHud.showToast(message: "\"下载完成\"");
    }, failure: (error) {
    
    
      // 下载出错
      FlutterLoadingHud.showToast(message: error.message);
    });
}

ダウンロードが完了したら、インストールして操作を開始できます。

2. APKのインストールと起動

APK のインストールと起動にはネイティブ プラグインが必要です。

2.1. ネイティブプラグイン flutter_package_manager の作成

Flutter プラグインを作成するために使用するツールは Android Studio です。

以下を設定します。

  • プロジェクト名
  • プロジェクトの場所
  • 説明
  • プロジェクトの種類: プラグイン
  • Android言語
  • iOS言語
  • プラットフォーム

写真が示すように

ここに画像の説明を挿入します

installThenStartを実装する必要があります

/// An implementation of [FlutterPackageManagerPlatform] that uses method channels.
class MethodChannelFlutterPackageManager extends FlutterPackageManagerPlatform {
    
    
  /// The method channel used to interact with the native platform.
  
  final methodChannel = const MethodChannel('flutter_package_manager');

  
  Future<String?> getPlatformVersion() async {
    
    
    final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
    return version;
  }

  
  Future<void> installThenStart(String apkFilePath, String activity) async {
    
    
    final result = await methodChannel.invokeMethod<void>('installThenStart');
    return result;
  }
}

installThenStart が定義されており、パラメーターとして apkFilePath と activity が必要であることがわかります。

サイレントインストールする必要があるため、Android 側に実装されます (APK はバックグラウンドでインストールされ、インストールインターフェイスのプロンプトは表示されません)。

public class FlutterPackageManager implements MethodCallHandler {
    
    
    private static final String TAG = "FlutterPackageManager";

    private final Registrar registrar;

    /**
     * Plugin registration.
     */
    public static void registerWith(Registrar registrar) {
    
    
        final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_package_manager");
        channel.setMethodCallHandler(new FlutterPackageManager(registrar));
    }

    private FlutterPackageManager(Registrar registrar) {
    
    
        this.registrar = registrar;
    }

    
    public void onMethodCall(MethodCall call, Result result) {
    
    
        if (call.method.equals("getPlatformVersion")) {
    
    
            result.success(android.os.Build.VERSION.RELEASE);
        } else if (call.method.equals("installThenStart")) {
    
    
            String path = call.arguments['filePath'];
	    String activity = call.arguments['activity'];
	    installApk(path, activity);
        } else {
    
    
            result.notImplemented();
        }
    }

    void installApk(String path, String activity) {
    
    
    	// root权限静默安装实现 实现实际使用的是su pm install -r filePath命令。
	Process process = null; 
   	OutputStream out = null; 
   	InputStream in = null; 
   	try {
    
     
   		// 请求root 
   		process = Runtime.getRuntime().exec("su"); 
   		out = process.getOutputStream(); 
   		// 调用安装 
   		out.write(("pm install -r " + path + "\n").getBytes()); 
   		in = process.getInputStream(); 
   		int len = 0; 
   		byte[] bs = new byte[256]; 
   		while (-1 != (len = in.read(bs))) {
    
     
   		String state = new String(bs, 0, len); 
   		if (state.equals("Success\n")) {
    
     
    			//安装成功后的操作 
			startActivity(activity);
     		} 
    	   } 
   	} catch (IOException e) {
    
     
    		e.printStackTrace(); 
   	} catch (Exception e) {
    
     
    		e.printStackTrace(); 
   	} finally {
    
     
    		try {
    
     
     			if (out != null) {
    
     
      				out.flush(); 
      				out.close(); 
     			} 
     			if (in != null) {
    
     
      				in.close(); 
     			} 
    		} catch (IOException e) {
    
     
     			e.printStackTrace(); 
    		} 
   	} 
 
    }

    void startActivity(String activity) {
    
    
        // activity格式为'com.laileshuo.app/com.laileshuo.app.MainActivity'
    	Intent mIntent = new Intent(); 
	val componentName = ComponentName(this, activity)
	val intent = Intent().setComponent(componentName)
	startActivity(intent)
    }
}

もちろん、プロジェクト内の AndroidManifest.xml も次のように調整する必要があります。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.laileshuo.app">
   <application
        tools:replace="android:label"
        android:label="我的应用"
        android:name="${
      
      applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name="com.laileshuo.app.MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- Specifies an Android theme to apply to this Activity as soon as
                 the Android process has started. This theme is visible to the user
                 while the Flutter UI initializes. After that, this theme continues
                 to determine the Window background behind the Flutter UI. -->
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
</manifest>

2.2. 非 root 環境にインストールされている場合は、open_file プラグインを使用できます。

プラグインは pubspec.yaml に導入する必要があります

dependencies:
  open_file: ^3.3.2

コードを直接使用して APK をインストールできます

import 'package:open_file/open_file.dart';

OpenFile.open(apkFilePath);

FileProviderに関して他のプラグインと競合する場合、AndroidManifest.xmlを設定する必要があります

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          package="xxx.xxx.xxxxx">
    <application>
        ...
        <provider
                android:name="androidx.core.content.FileProvider"
                android:authorities="${
      
      applicationId}.fileProvider"
                android:exported="false"
                android:grantUriPermissions="true"
                tools:replace="android:authorities">
            <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/filepaths"
                    tools:replace="android:resource" />
        </provider>
    </application>
</manifest>

3. まとめ

Flutter 開発の実践 - アプリケーションの更新 APK のダウンロード、APK のインストール、アプリケーションの実装の開始。開発プロセスでは、apk ファイルの新しいバージョンを更新してダウンロードし、次にアプリケーション更新 apk をダウンロードし、apk をインストールして、アプリケーションを起動する必要が頻繁に発生します。Flutter プロジェクトで APK をダウンロードし、現在のバージョンと更新してインストールする必要があるバージョンを比較し、VersionCode を判断して新しいバージョンの APK のダウンロードを決定します。内容が多く、説明が正確ではないかもしれませんが、ご容赦ください。

https://blog.csdn.net/gloryFlow/article/details/133440529

勉強して記録し、日々改善を続けてください。

おすすめ

転載: blog.csdn.net/gloryFlow/article/details/133440529