Flutter에서 인앱 업데이터(OTA) 빌드
여러 면에서 Flutter는 크로스 플랫폼 모바일 애플리케이션을 구축하기 위한 환상적인 프레임워크이지만 플랫폼에 구애받지 않는 기능을 개발할 때 많은 사람들이 플랫폼 채널 코드에 의존하는 것 같습니다.
다음 세 가지 이유로 Dart에서 가능한 한 많은 코드를 유지하려고 합니다.
따라서 코드를 Dart에 유지하는 데 중점을 둔 것처럼 이론적으로 우리의 주요 장애물은 파일, 시스템 권한으로 작업한 다음 인텐트를 시작해야 한다는 것입니다. Dart의 파일 지원은 실제로 문제가 아니며 편리한 플러그인으로 시스템 권한을 극복할 수 있지만 의도를 위해 플랫폼 채널에 의존해야 했지만 약 10줄의 간단한 동기 코드입니다.
1단계: 시스템 권한
simple_permissions
라는 Flutter 플러그인 덕분에 이것은 큰 문제가 되지 않았습니다.import 'package:simple_permissions/simple_permissions.dart';
// ...
bool permissionStatus = await SimplePermissions.checkPermission(Permission.WriteExternalStorage);
if(!permissionStatus) permissionStatus = (await SimplePermissions.requestPermission(Permission.WriteExternalStorage)) == PermissionStatus.authorized;
uses-permission
태그를 AndroidManifest.xml
태그에 추가해야 합니다.<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2단계: 파일 시스템
내장된
dart:io
라이브러리와 path-provider
플러그인 사이에서 Flutter의 플랫폼에 구애받지 않는 특성으로 인해 이론적으로는 문제가 있지만 Flutter는 실제로 파일 조작을 위한 뛰어난 API를 제공합니다.import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:http/http.dart' as http;
// Don't forget to check that you have Filesystem permissions or this will fail!
class FileIO {
static const downloadDirReference = "/.apollo";
///
/// Download and install the app at [url].
/// You should call this method *after* querying your server for any available updates
/// and getting the download link for the update.
///
static Future<void> runInstallProcedure(String url) async {
/ **************************************** /
/* Setup and clean directories */
/ **************************************** /
// Instantiate a directory object
final downloadDir = new Directory(
(await getExternalStorageDirectory()).path + downloadDirReference
);
// Create the directory if it doesn't already exist.
if(!await downloadDir.exists()) await downloadDir.create();
// Instantiate a file object (in this case update.apk within our download folder)
final downloadFile = new File("${downloadDir.path}/update.apk");
// Delete the file if it already exists.
if(await downloadFile.exists()) await downloadFile.delete();
/ **************************************** /
/* Download the APK */
/ **************************************** /
// Instantiate an HTTP client
http.Client client = new http.Client();
// Make a request and get the response bytes.
var req = await client.get(url); // (The link to your APK goes here)
var bytes = req.bodyBytes;
// Write the response bytes to our download file.
await downloadFile.writeAsBytes(bytes);
// TODO: Trigger intent.
}
}
Dart에서는 디렉토리를 참조하기 위해
Directory
클래스를 사용하고 파일을 참조하기 위해 File
클래스를 사용합니다. 제 생각에는 이것은 Java보다 훨씬 더 논리적이고 적절한 이름입니다.모든 것이 매우 자명하며 라이브러리에 내장된 Darts를 사용하면 파일을 다운로드하는 것이 매우 간편합니다.
참고: Android N 지원
Flutter와 관련이 없지만 설정하는 데 약간의 파고가 필요했기 때문에 이것을 포함했습니다.
<manifest >
<application>
<!-- ... -->
<provider
android:name="xyz.apollotv.kamino.OTAFileProvider"
android:authorities="xyz.apollotv.kamino.provider"
android:exported="false"
android:grantUriPermissions="true">
<!-- The @xml/filepaths file (see below) is located at /android/app/src/main/res/xml/filepaths.xml
relative to the Flutter project root. -->
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
</application>
</manifest>
package xyz.apollotv.kamino;
import android.support.v4.content.FileProvider;
// You need to reference this FileProvider in your AndroidManifest.xml
public class OTAFileProvider extends FileProvider {}
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- In our example, the APK is downloaded to the /storage/emulated/0/.apollo/ folder. -->
<external-path name=".apollo" path=".apollo/"/>
</paths>
Android 매니페스트 파일의
application
태그 안에 파일 공급자 클래스를 참조하는 provider
태그를 포함해야 합니다. 이 태그 안에 공급자가 액세스할 수 있는 모든 파일 경로를 나열하는 meta-data
태그가 있어야 합니다. (filepaths.xml
참조).FileProvider에 대한 자세한 내용은 https://developer.android.com/reference/android/support/v4/content/FileProvider을 참조하십시오.
3단계: 플랫폼 채널
마지막 단계는
ACTION_INSTALL_PACKAGE
인텐트를 실행하는 것입니다. 기본 플랫폼 채널을 설정하여 시작해야 합니다.OTAHelper.installOTA(downloadFile.path);
class OTAHelper {
// Replace xyz.apollotv.kamino with your package.
static const platform = const MethodChannel('xyz.apollotv.kamino/ota');
static Future<void> installOTA(String path) async {
try {
await platform.invokeMethod('install', <String, dynamic>{
"path": path
});
} on PlatformException catch (e) {
print("Error installing update: $e");
}
}
}
마지막으로
MainActivity.java
파일을 편집하여 MethodChannel
를 선언하고 코드를 실행하여 인텐트를 호출합니다.파일을 외부 메모리에 다운로드했기 때문에 여기에는 특별히 고급 개념이 없으므로 액세스하고 설치를 트리거하기만 하면 됩니다.
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
new MethodChannel(getFlutterView(), "xyz.apollotv.kamino/ota").setMethodCallHandler((methodCall, result) -> {
if(methodCall.method.equals("install")){
if(installOTA(methodCall.argument("path"))){
result.success(true);
}else{
result.error("ERROR", "An error occurred whilst installing OTA updates.", null);
}
return;
}
result.notImplemented();
});
}
private boolean installOTA(String path){
try {
Uri fileUri = Uri.parse("file://" + path);
Intent intent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// This line is important: after Android N, an authority must be provided to access files for an app.
Uri apkUri = OTAFileProvider.getUriForFile(getApplicationContext(), "xyz.apollotv.kamino.provider", new File(path));
intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
getApplicationContext().startActivity(intent);
return true;
}catch(Exception ex){
System.out.println("[Platform] Error during OTA installation.");
System.out.println(ex.getMessage());
return false;
}
}
}
그러면 OTA 설치가 시작됩니다!
Reference
이 문제에 관하여(Flutter에서 인앱 업데이터(OTA) 빌드), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/samjakob/building-an-in-app-updater-ota-in-flutter-11p9텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)