Unity获取手机本地应用以及调起apk安装、启动app、安装完成回调
1、获取手机本地应用。
创建AppInfo类和AppUtils类,用于接收获取到的应用列表。
Android层代码AppInfo:
public class AppInfo { private Drawable image; private String appName; private String packageName; public AppInfo() { } public Drawable getImage() { return image; } public void setImage(Drawable image) { this.image = image; } public String getAppName() { return appName; } public void setAppName(String appName) { this.appName = appName; } public String getPackageName() { return packageName; } public void setPackageName(String packageName) { this.packageName = packageName; } }
Android层代码AppUtils:
public class AppUtils { private static final String TAG = "AppUtils"; public static List<AppInfo> scanLocalInstallAppList(PackageManager packageManager) { List myAppInfos = new ArrayList(); try { List packageInfos = packageManager.getInstalledPackages(0); for (int i = 0; i < packageInfos.size(); i++) { PackageInfo packageInfo = (PackageInfo) packageInfos.get(i); //过滤掉系统app if ((ApplicationInfo.FLAG_SYSTEM & packageInfo.applicationInfo.flags) != 0) { continue; } AppInfo myAppInfo = new AppInfo(); String appName = packageInfo.applicationInfo.loadLabel(packageManager).toString(); myAppInfo.setAppName(appName); myAppInfo.setPackageName(packageInfo.packageName); if (packageInfo.applicationInfo.loadIcon(packageManager) == null) { continue; } myAppInfo.setImage(packageInfo.applicationInfo.loadIcon(packageManager)); myAppInfos.add(myAppInfo); } } catch (Exception e) { Log.e(TAG, "获取应用包信息失败"); } return myAppInfos; } }
Android层代码获取代码:
List<AppInfo> appInfos = AppUtils.scanLocalInstallAppList(app.getPackageManager()); //app为主activity的单例,也就是onCreate里设置app=this。 for(int k=0;k<appInfos.size();k++) { String s1 = appInfos.get(k).getAppName();//应用名 String s2 = appInfos.get(k).getPackageName();//应用包名com.xxx.xx.xx Drawable dw = appInfos.get(k).getImage();//应用的icon }
//安卓层获取这些信息后,再传递给Unity。
2、Unity调起APK的安装。
Unity代码:
设置apk的路径,假如在应用的虚拟目录下:
string apkPath = Application.persistentDataPath + "/" + apkName;
Android代码:
public static void InstallAPK(String filePath) { try { File apkFile = new File(filePath); if (apkFile.exists()) { Intent intent = new Intent(Intent.ACTION_VIEW); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Uri contentUri = FileProvider.getUriForFile(app, app.getPackageName()+".fileprovider", apkFile); intent.setDataAndType(contentUri, "application/vnd.android.package-archive"); } else { intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } app.startActivity(intent); } else { } } catch (Exception ex) { } }
Android需增加配置项,写在AndroidManifest.xml里。
权限:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
设置Provider:
${applicationId}为包名的变量,可以改写为com.xx.xx.xxx。
后面的.fileprovider需要与Android代码中的.fileprovider的名字保持一致。
provider_paths要与xml的名字保持一致。
<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" /> </provider>
res目录下的xml文件夹下增加provider_paths.xml,内容为:
<?xml version="1.0" encoding="utf-8"?> <paths> <external-path name="external_storage_root" path="." /> <files-path name="files-path" path="." /> <cache-path name="cache-path" path="." /> <!--/storage/emulated/0/Android/data/...--> <external-files-path name="external_file_path" path="." /> <!--代表app 外部存储区域根目录下的文件 Context.getExternalCacheDir目录下的目录--> <external-cache-path name="external_cache_path" path="." /> <!--配置root-path。这样子可以读取到sd卡和一些应用分身的目录,否则微信分身保存的图片,就会导致 java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/999/tencent/MicroMsg/WeiXin/export1544062754693.jpg,在小米6的手机上微信分身有这个crash,华为没有 --> <root-path name="root-path" path="" /> </paths>
3、启动App
//参数为app的包名,com.xx.xx.xx,如果app设置了禁止外部启动,那就无法调起。如果没有禁止外部调起,则能正常调起。
//app为主activity的单例,也就是onCreate里设置app=this。
public static void StartIntent(String pkgName) { try { Log.d("启动的包名:",pkgName); Intent intent = app.getPackageManager().getLaunchIntentForPackage(pkgName); app.startActivity(intent); } catch (Exception ex) { Log.d("启动的包名1:",ex.getMessage()); } }
4、安装APP回调。
不止是安装有回调、替换、卸载都有回调。
Android开启监听:
public static void ReceiverApk(){ try{ installPkg = ""; IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED); intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addDataScheme("package"); WXEntryActivity.app.registerReceiver(receiver, intentFilter);} catch (Exception ex) {} }
Android卸载监听:
public static void unReceiverApk(){ isReceiverApk=false; WXEntryActivity.app.unregisterReceiver(receiver); }
WXEntryActivity为主activity的名称。
app为主activity的单例,app=this.
Android回调:
private static BroadcastReceiver receiver=new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d("监听安装",intent.getAction().toString()); if (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)) { String packageName = intent.getData().getSchemeSpecificPart();
//安装 WXEntryActivity.mUnityPlayer.UnitySendMessage("Global","UnityReceiveAndroid","apkOperation|appInstall|" + packageName); } else if (intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)) { String packageName = intent.getData().getSchemeSpecificPart(); // Log.e("~~~apk", packageName + "替换成功"); WXEntryActivity.mUnityPlayer.UnitySendMessage("Global","UnityReceiveAndroid","apkOperation|appReplace|" + packageName); //jsbCallBack("appReplace",packageName); } else if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) { String packageName = intent.getData().getSchemeSpecificPart(); // Log.e("~~~apk", packageName + "卸载成功"); WXEntryActivity.mUnityPlayer.UnitySendMessage("Global","UnityReceiveAndroid","apkOperation|appRemove|" + packageName); //jsbCallBack("appRemove",packageName); } } };
WXEntryActivity.mUnityPlayer.UnitySendMessage为向Unity发送消息,通知Unity。
小时候我把老婆种到地下,长大了我能收获一大堆老婆!
我是威少,我是一名Unity游戏的主程,我为自己带盐,希望此文能给您一点点微不足道的帮助,祝你成功!