[英]How to create a .xapk file? Can I make it from a .apk and a .obb file?
[英]I am making an .XAPK installer application in flutter. with open_file package I can open normal .apk installation dialogue but how can I install .XAPK
As.XAPK 文件包含 1 个 base_apk 以及 obb 文件和一些其他 additional.apk 文件。 通过将 .XAPK 文件转换为 zip 然后解压缩它让我安装 base_apk 但该 APK 实际上不起作用,因为它没有与其他附加 APK 一起正确安装。 如何正确安装.XAPK 文件的所有 APK。(以下代码使用 Dart 语言,因为它是 Flutter APK)。
这是我的代码:
import 'dart:io';
import 'package:archive/archive.dart';
import 'package:package_archive_info/package_archive_info.dart';
import 'package:path_provider/path_provider.dart';
abstract class XapkInstaller { static install({ required String apkPath }) async {
late List<FileSystemEntity> allFiles, apkFiles;
late PackageArchiveInfo appInfo;
late String appPackageName;
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
String appName = apkPath.split("/").last.replaceAll(".xapk", "");
String zipFilePath = tempDir.path + "/${appName}_zip";
// this function convert xapk in zip file and moves in appname_zip dirctory
_moveFile(File(apkPath), zipFilePath, appName);
final bytes = File(zipFilePath + "/$appName" + ".zip").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 &&
appPackageName == App.apkName(apkPath: filePath)) {
try {
// moving real app from extracting folder to APKdojo folder
File(filePath)
.copySync(await App.getApksDirectory() + "/$appName.apk");
// moving obb file to android/obb folder
_moveObbToAndroidDir(allFiles, appPackageName);
// showing popup to install app
await OpenFile.open(filePath);
// deleting .xapk file after moving real extracted app in the APKdojo folder and obb file into android folder
File(await App.getApksDirectory() + "/$appName" + ".xapk").delete();
} catch (e) {
//error in installing
}
}
}
// clearing cache file after installing xapk
Future.delayed(const Duration(seconds: 180), () {
tempDir.deleteSync(recursive: true);
tempDir.create();
}); }
static _moveFile(File sourceFile, String newPath, String appname) async {
if (!Directory(newPath).existsSync()) Directory(newPath).createSync();
final String zipFilePath = "$newPath/" + appname + ".zip";
try {
return sourceFile.copySync(zipFilePath);
} on FileSystemException {
// if rename fails, copy the source file and then delete it
await sourceFile.copy(zipFilePath);
await sourceFile.delete();
} }
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 = await App.internalStoragePath() +
"/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);
}
}
} } }
如果您仍在尝试安装 .xapk 文件,我正在分享一段对我有帮助的代码。 我正在使用这些包:
存档(对于所有提取为 zip 逻辑)
device_apps (在您没有所需权限的情况下打开“设置”应用程序)
open_filex (以 Android 意图打开 apk 文件)
package_archive_info (从.apk包中获取信息)
path_provider (获取目录和路径)
permission_handler (请求安装权限)
和file_picker ,因为我使用 package 启动了选择文件的方法。
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 文件的权限,一切就绪。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.