簡體   English   中英

我正在 flutter 中制作一個 .XAPK 安裝程序應用程序。使用 open_file package 我可以打開 normal.apk 安裝對話框,但如何安裝.XAPK

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM