A more robust self hosted OTA updates implementation

This commit is contained in:
2026-03-13 07:15:28 +08:00
parent 9267ebee2c
commit 9bbaf67fef
8 changed files with 852 additions and 164 deletions
+10
View File
@@ -71,6 +71,16 @@
android:name="id.flutter.flutter_background_service.BackgroundService"
android:foregroundServiceType="location"
tools:replace="android:foregroundServiceType" />
<!-- FileProvider for OTA plugin (ota_update) -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.ota_update_provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/ota_update_file_paths" />
</provider>
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
@@ -1,5 +1,49 @@
package com.example.tasq
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import android.content.Intent
import android.net.Uri
import androidx.core.content.FileProvider
import java.io.File
class MainActivity : FlutterFragmentActivity()
class MainActivity : FlutterFragmentActivity() {
private val CHANNEL = "tasq/ota"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, _ ->
when (call.method) {
"openUnknownSources" -> {
try {
val intent = Intent(android.provider.Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
intent.data = Uri.parse("package:" + applicationContext.packageName)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
applicationContext.startActivity(intent)
} catch (e: Exception) {
// ignore and return
}
}
"installApk" -> {
try {
val path = call.argument<String>("path") ?: return@setMethodCallHandler
val file = File(path)
val authority = applicationContext.packageName + ".ota_update_provider"
val uri = FileProvider.getUriForFile(applicationContext, authority, file)
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(uri, "application/vnd.android.package-archive")
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
applicationContext.startActivity(intent)
} catch (e: Exception) {
// ignore - caller will surface error
}
}
else -> {
// no-op
}
}
}
}
}
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Allow access to common app storage locations used by OTA plugin -->
<external-path name="external_files" path="." />
<external-files-path name="external_files_app" path="." />
<cache-path name="cache" path="." />
<external-cache-path name="external_cache" path="." />
<files-path name="files" path="." />
</paths>