diff --git a/android/android/app/src/main/AndroidManifest.xml b/android/android/app/src/main/AndroidManifest.xml
index 3c533d4..b287d8a 100644
--- a/android/android/app/src/main/AndroidManifest.xml
+++ b/android/android/app/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
+
+
+
+
+
diff --git a/android/android/app/src/main/java/com/ariacockpit/ApkInstallerModule.kt b/android/android/app/src/main/java/com/ariacockpit/ApkInstallerModule.kt
new file mode 100644
index 0000000..6c676a7
--- /dev/null
+++ b/android/android/app/src/main/java/com/ariacockpit/ApkInstallerModule.kt
@@ -0,0 +1,44 @@
+package com.ariacockpit
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Build
+import androidx.core.content.FileProvider
+import com.facebook.react.bridge.ReactApplicationContext
+import com.facebook.react.bridge.ReactContextBaseJavaModule
+import com.facebook.react.bridge.ReactMethod
+import com.facebook.react.bridge.Promise
+import java.io.File
+
+class ApkInstallerModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
+ override fun getName() = "ApkInstaller"
+
+ @ReactMethod
+ fun install(filePath: String, promise: Promise) {
+ try {
+ val file = File(filePath)
+ if (!file.exists()) {
+ promise.reject("FILE_NOT_FOUND", "APK nicht gefunden: $filePath")
+ return
+ }
+
+ val context = reactApplicationContext
+ val uri: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file)
+ } else {
+ Uri.fromFile(file)
+ }
+
+ val intent = Intent(Intent.ACTION_VIEW).apply {
+ setDataAndType(uri, "application/vnd.android.package-archive")
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ }
+
+ context.startActivity(intent)
+ promise.resolve(true)
+ } catch (e: Exception) {
+ promise.reject("INSTALL_ERROR", e.message, e)
+ }
+ }
+}
diff --git a/android/android/app/src/main/java/com/ariacockpit/ApkInstallerPackage.kt b/android/android/app/src/main/java/com/ariacockpit/ApkInstallerPackage.kt
new file mode 100644
index 0000000..2282536
--- /dev/null
+++ b/android/android/app/src/main/java/com/ariacockpit/ApkInstallerPackage.kt
@@ -0,0 +1,16 @@
+package com.ariacockpit
+
+import com.facebook.react.ReactPackage
+import com.facebook.react.bridge.NativeModule
+import com.facebook.react.bridge.ReactApplicationContext
+import com.facebook.react.uimanager.ViewManager
+
+class ApkInstallerPackage : ReactPackage {
+ override fun createNativeModules(reactContext: ReactApplicationContext): List {
+ return listOf(ApkInstallerModule(reactContext))
+ }
+
+ override fun createViewManagers(reactContext: ReactApplicationContext): List> {
+ return emptyList()
+ }
+}
diff --git a/android/android/app/src/main/java/com/ariacockpit/MainApplication.kt b/android/android/app/src/main/java/com/ariacockpit/MainApplication.kt
index adf68f7..16ab703 100644
--- a/android/android/app/src/main/java/com/ariacockpit/MainApplication.kt
+++ b/android/android/app/src/main/java/com/ariacockpit/MainApplication.kt
@@ -18,8 +18,7 @@ class MainApplication : Application(), ReactApplication {
object : DefaultReactNativeHost(this) {
override fun getPackages(): List =
PackageList(this).packages.apply {
- // Packages that cannot be autolinked yet can be added manually here, for example:
- // add(MyReactNativePackage())
+ add(ApkInstallerPackage())
}
override fun getJSMainModuleName(): String = "index"
diff --git a/android/android/app/src/main/res/xml/file_paths.xml b/android/android/app/src/main/res/xml/file_paths.xml
new file mode 100644
index 0000000..d2e2c8d
--- /dev/null
+++ b/android/android/app/src/main/res/xml/file_paths.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/android/src/screens/SettingsScreen.tsx b/android/src/screens/SettingsScreen.tsx
index a49fe74..02367b4 100644
--- a/android/src/screens/SettingsScreen.tsx
+++ b/android/src/screens/SettingsScreen.tsx
@@ -748,11 +748,21 @@ const SettingsScreen: React.FC = () => {
{'\u00DC'}ber
ARIA Cockpit
- Version 0.0.2.8
+ Version {require('../../package.json').version}
Stefans Kommandozentrale f{'\u00FC'}r ARIA.{'\n'}
Gebaut mit React Native + TypeScript.
+ {
+ const updateService = require('../services/updater').default;
+ updateService.checkForUpdate();
+ Alert.alert('Update-Check', 'Pruefe auf neue Version...');
+ }}
+ >
+ Auf Updates pr{'\u00FC'}fen
+
{/* Platz am Ende */}
diff --git a/android/src/services/updater.ts b/android/src/services/updater.ts
index 90e79a3..b60c4a9 100644
--- a/android/src/services/updater.ts
+++ b/android/src/services/updater.ts
@@ -7,12 +7,13 @@
* 3. App zeigt Benachrichtigung → User bestaetigt → Download + Install
*/
-import { Alert, Linking, Platform } from 'react-native';
+import { Alert, Linking, Platform, NativeModules } from 'react-native';
import RNFS from 'react-native-fs';
import rvs, { RVSMessage } from './rvs';
-// Aktuelle App-Version (aus package.json via Build)
-const APP_VERSION = '0.0.2.3'; // TODO: aus nativer Build-Config lesen
+// Version aus package.json (wird beim Build eingebettet)
+const packageJson = require('../../package.json');
+const APP_VERSION = packageJson.version || '0.0.0.0';
type UpdateCallback = (info: UpdateInfo) => void;
@@ -116,9 +117,17 @@ class UpdateService {
const fileSize = await RNFS.stat(destPath);
console.log(`[Update] APK gespeichert: ${destPath} (${(parseInt(fileSize.size) / 1024 / 1024).toFixed(1)}MB)`);
- // APK installieren (oeffnet Android-Installer)
+ // APK installieren via natives ApkInstaller Module (FileProvider + Intent)
if (Platform.OS === 'android') {
- await Linking.openURL(`file://${destPath}`);
+ try {
+ const { ApkInstaller } = NativeModules;
+ await ApkInstaller.install(destPath);
+ } catch (installErr: any) {
+ Alert.alert(
+ 'APK heruntergeladen',
+ `Version ${info.version} gespeichert.\n\nBitte manuell installieren:\nDateimanager → ${apkData.fileName} antippen.\n\n(${installErr.message})`,
+ );
+ }
}
} catch (err: any) {
console.error(`[Update] Fehler: ${err.message}`);