I want to make an app with flutter which can install other apks. When I try to install apks using the flutter_app_installer or app_installer packages I get a pop-up on the phone saying: "An error occurred while parsing the package."
Usually this error message means the .apk file is damaged. However, using the file explorer on android I can install the apk just fine.
Furthermore, there could be a permission problem. My App asks for Storage permission and permission to install apks, I granted those.
I've tried different flutter-packages for installing apks, as mentioned above. Both throw the same error message.
When I provide a wrong path to the apk on purpose I dont get an error message. I did that to verify that the path to the apk is correct.
I tried running this on two android devices.
In the flutter debug console is no error message shown, only on the phone.
Here the error message (on a german phone):

I tried googling and asking chattie, cant find any helpful advice. I am stuck at this point for a while.
This is my flutter code:
import 'dart:io';
import 'package:app_installer/app_installer.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:path/path.dart' as path;
import 'package:flutter_app_installer/flutter_app_installer.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Request runtime permission
await Permission.storage.request();
await Permission.requestInstallPackages.request();
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: TextButton(
onPressed: () async {
await AppInstaller.installApk(
"storage/emulated/0/Download/test.apk",
);
},
child: const Text('Install App'),
),
),
),
);
}
}
This is my AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.apk_install_test">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application
android:label="apk_install_test"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".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>
<!-- Provider -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<!-- 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>
after 3 days of pain I made it :)
Here is what I did: First of all, I tried every flutter plugin that installs apks, none worked. Then I switched to an intend-based approach, which had even more problems. The open_file plugin is another way, but I didnt get that right either.
So I had to dig deeper.
In the newer android versions, storage permissions are much stricter. Therefore most file IO is not possible with basic permissions. I had to request MANAGE_EXTERNAL_STORAGE using Permission.manageExternalStorage.request()
Only with that permission I was able to access the Downloads folder. Of course, you have to add the downloads folder to your file_paths.xml like this: <external-path name="external_files_download" path="Download" />
My App wasnt meant to install apks from the downloads folder but apks downloaded by the app directly, which are stored in the apps own data folder. This data folder is a protected folder as I learned, which forbids other apps (like apk-installers) from reading the file.
I had to write this function to copy apks from internal to external storage. Only after that I could access it and install it:
/// Copies the given file to the external storage directory and returns the new file
/// Needed, because the app can only install apks from the external storage directory
Future<File> copyFileToExternalStorage(File sourceFile) async {
String fileName = sourceFile.path.split('/').last; // Extract the file name
Directory? externalDir = await getExternalStorageDirectory(); // Get external directory
if (externalDir == null) {
throw Exception("External storage directory not found");
}
File destinationFile = File('${externalDir.path}/$fileName'); // Create new file at destination path
await sourceFile.copy(destinationFile.path); // Copy source file to destination
return destinationFile; // Return the new file object
}
With these changes I could use the apk installer plugins from pub.dev. It is important to notice, that different plugins reqiure a different provider name in AndroidManifest.xml So remember to name it, as stated in the plugin documentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With