Flutter安卓APK安装包管理插件flutter_android_package_installer的使用

Flutter安卓APK安装包管理插件flutter_android_package_installer的使用

本库基于android_package_installer改造,适配最新Flutter 3.24.0版本,并修改了以下内容:

  • 原库的installApk方法调用的是PackageInstaller.Session方法实现的。PackageInstaller我这里测试就没成功过。所以这里更改了此方法的默认实现为Intent.ACTION_VIEW
  • 原库的installApk方法改名为installApkSession
  • 修改compileSdk 34
  • 新增getPlatformVersion方法
  • 新增openAppMarket方法
  • 新增openAppSettingDetail方法

补充一点

FileProvider资源配置需要包含root-path:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
    <root-path name="root" path="" />
</paths>

android_package_installer

A Flutter plugin for installing Android package from apk file. 插件使用Android Package Installer,并且需要最小API级别版本21。

使用

import 'package:flutter_android_package_installer/flutter_android_package_installer.dart';

int? statusCode = await AndroidPackageInstaller.installApk(apkFilePath: '/sdcard/Download/com.example.apk');
if (code != null) {
  PackageInstallerStatus installationStatus = PackageInstallerStatus.byCode(statusCode);
  print(installationStatus.name);
}

要安装Android包,应用程序需要权限。你可以使用permission_handler包来请求它们。

设置

  1. <projectDir>/android/app/src/main/AndroidManifest.xml文件中添加权限到你的AndroidManifest.xml文件:
<manifest xmlns:tools="http://schemas.android.com/tools" ...>

  <!-- ADD THESE PERMISSIONS -->
  <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  
  <application ...>
    <activity ...>

      ...

      <!-- ADD THIS INTENT FILTER -->
      <intent-filter>
        <action
            android:name="com.android_package_installer.content.SESSION_API_PACKAGE_INSTALLED"
            android:exported="false"/>
      </intent-filter>
    </activity>

    <!-- ADD THIS PROVIDER -->
    <provider
      android:name="androidx.core.content.FileProvider"
      android:authorities="${applicationId}"
      android:grantUriPermissions="true">
      <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths"/>
    </provider>
  </application>
</manifest>
  1. 检查外部路径在你的自定义路径文件中。如果不存在,在<projectDir>/android/app/src/main/res/xml/file_paths.xml创建它:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

示例代码

import 'package:flutter_android_package_installer/flutter_android_package_installer.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:permission_handler/permission_handler.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _installationStatus = '';
  final TextEditingController _filePathFieldController =
      TextEditingController(text: '');

  [@override](/user/override)
  void initState() {
    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('插件示例'),
        ),
        body: Center(
          child: Padding(
              padding: const EdgeInsets.all(30.0),
              child: Column(
                children: [
                  Row(
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      Expanded(
                          child: TextField(
                              controller: _filePathFieldController,
                              decoration: const InputDecoration(
                                  labelText: "APK文件路径",
                                  hintText: "输入路径"))),
                      _button('选择文件', () async {
                        FilePickerResult? result = await FilePicker.platform
                            .pickFiles(
                                type: FileType.custom,
                                allowedExtensions: ['apk']);
                        if (result != null) {
                          setState(() {
                            _filePathFieldController.text =
                                result.files.single.path!;
                            _installationStatus = '';
                          });
                        }
                      }),
                    ],
                  ),
                  const SizedBox(height: 10),
                  Text(
                      'PackageManager安装状态: $_installationStatus'),
                  const SizedBox(height: 30),
                  _button('安装APK文件会话', () async {
                    if (_filePathFieldController.text.isNotEmpty) {
                      setState(() {
                        _installationStatus = '';
                      });
                      try {
                        int? code =
                            await AndroidPackageInstaller.installApkSession(
                                apkFilePath: _filePathFieldController.text);
                        if (code != null) {
                          setState(() {
                            _installationStatus =
                                PackageInstallerStatus.byCode(code).name;
                          });
                        }
                      } on PlatformException {
                        print('错误在平台。安装APK文件失败。');
                      }
                    }
                  }),
                  _button('安装APK文件', () async {
                    if (_filePathFieldController.text.isNotEmpty) {
                      setState(() {
                        _installationStatus = '';
                      });
                      try {
                        int? code = await AndroidPackageInstaller.installApk(
                            apkFilePath: _filePathFieldController.text);
                        if (code != null) {
                          setState(() {
                            _installationStatus =
                                PackageInstallerStatus.byCode(code).name;
                          });
                        }
                      } on PlatformException {
                        print('错误在平台。安装APK文件失败。');
                      }
                    }
                  }),
                  _button('获取平台版本', () async {
                    try {
                      String? platformVersion =
                          await AndroidPackageInstaller.platformVersion;
                      if (platformVersion != null) {
                        setState(() {
                          _installationStatus = platformVersion;
                        });
                      }
                    } on PlatformException {
                      print('错误在平台。安装APK文件失败。');
                    }
                  }),
                  _button('打开应用市场', () async {
                    try {
                      await AndroidPackageInstaller.openAppMarket();
                    } on PlatformException {
                      print('错误在平台。安装APK文件失败。');
                    }
                  }),
                  _button('打开应用设置详情', () async {
                    try {
                      await AndroidPackageInstaller.openAppSettingDetails();
                    } on PlatformException {
                      print('错误在平台。安装APK文件失败。');
                    }
                  }),
                  const Spacer(),
                  SizedBox(
                    child: Column(children: [
                      const Text('权限:'),
                      _button('外部存储',
                          () => _requestPermission(Permission.storage)),
                      _button(
                          '请求安装包',
                          () => _requestPermission(
                              Permission.requestInstallPackages)),
                      _button(
                          '管理外部存储\n(适用于Android 11+目标)',
                          () => _requestPermission(
                              Permission.manageExternalStorage)),
                    ]),
                  ),
                ],
              )),
        ),
      ),
    );
  }

  ElevatedButton _button(String text, VoidCallback? onPressed) {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(text),
    );
  }

  void _requestPermission(Permission permission) async {
    var status = await permission.status;
    if (status.isDenied) {
      await permission.request();
    }
  }
}

更多关于Flutter安卓APK安装包管理插件flutter_android_package_installer的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter安卓APK安装包管理插件flutter_android_package_installer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


flutter_android_package_installer 是一个 Flutter 插件,用于在 Android 设备上管理和安装 APK 文件。它允许你在 Flutter 应用程序中触发 APK 的安装过程,而无需用户手动操作。

以下是如何使用 flutter_android_package_installer 插件的步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 flutter_android_package_installer 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_android_package_installer: ^1.0.0  # 请使用最新版本

然后运行 flutter pub get 来安装依赖。

2. 导入插件

在你的 Dart 文件中导入插件:

import 'package:flutter_android_package_installer/flutter_android_package_installer.dart';

3. 使用插件安装 APK

你可以使用 FlutterAndroidPackageInstaller.installApk 方法来安装 APK 文件。以下是一个简单的示例:

import 'package:flutter/material.dart';
import 'package:flutter_android_package_installer/flutter_android_package_installer.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('APK Installer Example'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              String apkPath = '/sdcard/Download/example.apk'; // APK 文件路径
              try {
                await FlutterAndroidPackageInstaller.installApk(apkPath);
                print('APK installed successfully');
              } catch (e) {
                print('Failed to install APK: $e');
              }
            },
            child: Text('Install APK'),
          ),
        ),
      ),
    );
  }
}

4. 处理权限

在 Android 设备上安装 APK 文件需要 REQUEST_INSTALL_PACKAGES 权限。确保你的 AndroidManifest.xml 文件中包含以下权限:

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

5. 处理 Android 10 及以上版本的存储权限

在 Android 10 (API 29) 及以上版本中,访问外部存储需要特殊的权限处理。你可能需要使用 Scoped StorageMediaStore 来获取文件的 URI。

6. 测试

确保你在真实的 Android 设备上测试此功能,因为模拟器可能不支持所有的权限和安装操作。

7. 处理安装结果

你可以根据安装结果来处理不同的场景,例如提示用户安装成功或失败。

try {
  await FlutterAndroidPackageInstaller.installApk(apkPath);
  // 安装成功
  showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: Text('Success'),
      content: Text('APK installed successfully'),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: Text('OK'),
        ),
      ],
    ),
  );
} catch (e) {
  // 安装失败
  showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: Text('Error'),
      content: Text('Failed to install APK: $e'),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: Text('OK'),
        ),
      ],
    ),
  );
}

8. 卸载 APK

flutter_android_package_installer 插件还支持卸载 APK。你可以使用 FlutterAndroidPackageInstaller.uninstallApk 方法来卸载指定包名的应用:

try {
  await FlutterAndroidPackageInstaller.uninstallApk('com.example.app');
  print('APK uninstalled successfully');
} catch (e) {
  print('Failed to uninstall APK: $e');
}
回到顶部