【发布时间】:2023-01-15 03:01:54
【问题描述】:
我想实现这个功能;
按下按钮后,将从具有以下路径的本地存储安装 .xapk 文件。
String _apkFilePath = '/storage/emulated/0/Download/filename.xapk';
【问题讨论】:
我想实现这个功能;
按下按钮后,将从具有以下路径的本地存储安装 .xapk 文件。
String _apkFilePath = '/storage/emulated/0/Download/filename.xapk';
【问题讨论】:
如果您仍在尝试安装 .xapk 文件,我正在分享一段对我有帮助的代码。我正在使用这些包:
archive(所有提取为 zip 逻辑)
device_apps(在您没有所需权限的情况下打开“设置”应用程序)
open_filex(用安卓intent打开apk文件)
package_archive_info(从.apk包中获取信息)
path_provider(获取目录和路径)
permission_handler(请求安装权限)
和file_picker,因为我使用该包使用选择的文件启动了该方法。
abstract class XapkInstaller {
static install({required PlatformFile file}) async {
late List<FileSystemEntity> allFiles, apkFiles;
late PackageArchiveInfo appInfo;
late String appPackageName;
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
String appName = file.path.toString().split("/").last.replaceAll(".apklis", "");
String zipFilePath = "${tempDir.path.replaceAll('/$appName.apklis', '')}/$appName.zip";
// this function convert xapk in zip file and moves in appname_zip directory
_moveFile(File(file.path.toString()), zipFilePath);
final bytes = File(zipFilePath).readAsBytesSync();
final archive = ZipDecoder().decodeBytes(bytes);
// Extract the contents of the Zip archive to disk app cache.
for (final file in archive) {
final String filename = file.name;
if (file.isFile) {
final data = file.content as List<int>;
File("${tempDir.path}/$appName/$filename")
..createSync(recursive: true)
..writeAsBytesSync(data);
} else {
Directory(tempPath).create(recursive: true);
}
}
final Directory myDir = Directory("${tempDir.path}/$appName");
allFiles = myDir.listSync(recursive: true, followLinks: true);
apkFiles = allFiles.where((element) => element.path.endsWith('.apk')).toList();
for (int x = 0; x < apkFiles.length; x++) {
final String filePath = apkFiles[x].path;
try {
appInfo = await PackageArchiveInfo.fromPath(filePath);
appPackageName = appInfo.packageName;
} catch (e) {
appInfo = PackageArchiveInfo(appName: "", packageName: "", version: "", buildNumber: "");
}
if (appInfo.appName.isNotEmpty) {
try {
// moving obb file to android/obb folder
_moveObbToAndroidDir(allFiles, appPackageName);
// showing popup to install app
if (await Permission.requestInstallPackages.request().isGranted) {
await OpenFilex.open(filePath);
} else {
DeviceApps.openAppSettings(appInfo.packageName);
}
} catch (e) {
//catch error in installing
}
}
}
// clearing cache file after installing xapk
Future.delayed(const Duration(seconds: 180), () {
tempDir.deleteSync(recursive: true);
tempDir.create();
});
}
static _moveObbToAndroidDir(List<FileSystemEntity> allFiles, String appPackageName) async {
for (int x = 0; x < allFiles.length; x++) {
final fileExtension = allFiles[x].path.split("/").last.split(".").last;
if (fileExtension == "obb") {
String filepath = allFiles[x].path;
String obbFileName = filepath.split("/").last.split(".").first;
String obbDirPath = "/Android/obb/$appPackageName";
// creating the directory inside android/obb folder to place obb files
if (!Directory(obbDirPath).existsSync()) {
Directory(obbDirPath).createSync();
}
// rename path should also contains filename i.e. whole path with filename and extension
final String renamePath = "$obbDirPath/$obbFileName.obb";
try {
// syncronus copying
File(filepath).copySync(renamePath);
} on FileSystemException {
// in case of exception copying asyncronushly
await File(filepath).copy(renamePath);
}
}
}
}
static Future<File> _moveFile(File sourceFile, String newPath) async {
try {
// prefer using rename as it is probably faster
return await sourceFile.rename(newPath);
} on FileSystemException catch (e) {
// if rename fails, copy the source file and then delete it
final newFile = await sourceFile.copy(newPath);
await sourceFile.delete();
return newFile;
}
}
}
我已经试过了,它确实有效,所以请记住更新 AndroidManifest 文件的权限,一切就绪。
【讨论】: