Android获得安装或者未安装的apk的信息:versionName, packageName, appIcon...


需求是这样的:我们的浏览器下载一个APK文件,把文件的下载路径交给系统的下载管理类:DownloadManager了,然后监听到下载完成后,就提示用户安装,弹出那个安装应用的界面。就是类似你从各个应用市场下载完应用后,也会提示你安装应用的。

你可以监听下载DownloadManager 的ACTION_DOWNLOAD_COMPLETE 这个ACTION,然后做你的逻辑处理,这个时候这个APK是没有安装的,如果想拿到应用的信息( versionCode, versionName, appIcon, packageName等)怎么取到呢?


1.先做第一个实验:有2个应用A,B,都以及安装好了,我想在B中拿到A的应用信息,就是上面标红色的信息:我做了实验,用下面的方法可以取到。

获取已安装apk的信息,这里比较简单,网上的资料也非常多,就不做过的的介绍
    private String getInstallAPKInfo(Context ctx,String pak) {
        //pak=com.aa.bb
        String versionName = null;
        PackageManager pm=ctx.getPackageManager();
        PackageInfo pakinfo;
        try {
            pakinfo = pm.getPackageInfo(pak, PackageManager.GET_ACTIVITIES);
            if (pakinfo!=null) {
                versionName=pakinfo.versionName;
            }

     // 测试后发现,下面这样能取到,直接调用loadIcon
//            Drawable icon = pakinfo.applicationInfo.loadIcon(pm);
//            img.setBackgroundDrawable(icon);

     // 测试后发现这样是取不到的,返回的是android的默认小绿色机器人的图标
     // 分析:可能传进去的content是B应用的context, 所以在B应用中无法得到A应用的icon,返回默认的logo。
            int iconId = pakinfo.applicationInfo.icon;
            Drawable icon2 = ctx.getResources().getDrawable(iconId);
            img.setBackgroundDrawable(icon2);

     // 测试后,发现这样也能取到
            Drawable icon3 = pm.getApplicationIcon(packageName);
            img.setBackgroundDrawable(icon3);

        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return versionName;
    }

2. 第二个实验,。在一个已经安装的APK中获取另一个未安装的APK的信息

下载的代码是网上都在传的,我做了2个测试,发现有点意思,一个测试是在系统应用中编译的,在android源码中直接mm编译的,按照下面的方法是可以取到的; 另一个是在一个普通的android项目中(就是新建一个Android Project),就取不到,我不知道这是否和系统签名的应用有关系。也看到网上有朋友说下面的代码根本取不到,也许他也是和我的第二个测试方法一样,在一个独立的app项目中测试的。

  /**
     * get un-installed apk package info
     * @param ctx
     * @param archiveFilePath
     * @return
     */
    private static String getUninstallAPKInfo(Context ctx,String archiveFilePath, TextView txt, ImageView img) {
        // archiveFilePath=Environment.getExternalStorageDirectory()+"/"+"TestB.apk"
        String versionName = null;
        String appName = null;
        String pakName = null;
        PackageManager pm = ctx.getPackageManager();
        PackageInfo pakinfo = pm.getPackageArchiveInfo(archiveFilePath, PackageManager.GET_ACTIVITIES);
        if (pakinfo != null) {
            ApplicationInfo appinfo=pakinfo.applicationInfo;
            versionName = pakinfo.versionName;
            Drawable icon=pm.getApplicationIcon(appinfo);
            appName = (String) pm.getApplicationLabel(appinfo);
            pakName = appinfo.packageName;
            
            String text = "versionName = " + versionName + " , appName = " + appName + " , pakName = " + pakName;
            txt.setText(text);
            img.setBackgroundDrawable(icon);

        } else {
            System.out.println("pakinfo == null");
        }
        
        return versionName;
    }


上面的源码这个链接中有:http://blog.csdn.net/johnsonblog/article/details/7604899


补充:获取未安装APK的签名信息,和获取versionCode其实差不多~
http://www.blogjava.net/TiGERTiAN/archive/2012/05/27/379322.html



到这里就涉及到Android 动态加载了
动态加载主要是加载未安装或者以及安装但是没有启动的应用的类或者资源文件。

1.这个老兄的这个博文应该是比较有价值的,通过反射获得未安装的APK的资源,比如:appIcon, versionName, packageName等;

http://kalogen.iteye.com/?page=3

里面提到的这个以及无法点击了,其实我看了下,就是这个类:packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java

借鉴的Android源码出处:

XXoo这个链接好长ooXX


2.用反射调用其他APP里的函数和资源

http://blog.sina.com.cn/s/blog_7bed7b2b01015dc0.html
http://blog.sina.com.cn/s/blog_7bed7b2b010169se.html


http://www.cnblogs.com/over140/archive/2011/11/23/2259367.html
http://www.cnblogs.com/over140/archive/2012/03/29/2423116.html
http://www.cnblogs.com/over140/archive/2012/04/19/2446119.html

http://www.blogjava.net/zh-weir/archive/2012/03/29/362294.html

http://wangleyiang.iteye.com/blog/1791947
http://blog.csdn.net/johnsonblog/article/details/7581070

4.补充:
为了测试动态加载,启动未安装的APK中的类,我根据下面文章做测试, 我开始把测试的3个apk 文件:TestRoomA, TestRoomB, TestRoomC放到/data/data/com.anhuioss.hall/apk/ 下,报这个错误,我又改到/storage/xxx/ 下,也报这个错误,后来没办法就看网上的答案,有个兄弟说放这里是可以的: 拷贝文件到/data/data/包名 目录下即可解决此问题经过测试确实可以了。
但是一直发现下面的问题,似乎是没有权限的问题,百度了一下,果然是这样的,在android4.1的时候改的:( 答案见链接)
java.lang.IllegalArgumentException: Optimized data directory /storage/sdcard0 is not owned by the current user. Shared storage cannot protect your application from code injection attacks.

参考答案链接:
http://www.oschina.net/question/162135_93054


最后总结,这种技术是否成熟,需要待定~需要做多次测试才好~
 


<?xml version="1.0" encoding="utf-8" standalone="no"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.dw.Dating.lua" android:versionName="22" android:versionCode="1" android:installLocation="preferExternal"> <!-- 添加必要的Unity兼容配置 --> <uses-feature android:glEsVersion="0x20000" /> <uses-feature android:name="android.hardware.touchscreen" android:required="false" /> <!-- 权限优化 --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- 移除Unity 5.3.8不支持的权限 --> <!-- 已移除:MOUNT_UNMOUNT_FILESYSTEMS, CHANGE_NETWORK_STATE, CHANGE_WIFI_STATE, INTERACT_ACROSS_USERS_FULL, android.webkit.permission.PLUGIN, com.android.launcher.permission.INSTALL_SHORTCUT --> <application android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="true" android:isGame="true" android:banner="@drawable/app_banner" android:hardwareAccelerated="true" <!-- 启用硬件加速提升性能 --> android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> <!-- 添加全屏主题 --> <!-- 关键Unity兼容配置 --> <activity android:name="com.unity3d.player.UnityPlayerActivity" <!-- 使用Unity标准Activity --> android:label="@string/app_name" android:screenOrientation="fullSensor" android:launchMode="singleTask" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LEANBACK_LAUNCHER" /> </intent-filter> <meta-data android:name="unityplayer.UnityActivity" android:value="true" /> </activity> <!-- 支付相关Activity保留 --> <activity android:name="com.fanwei.jubaosdk.cashier.CashierActivity" android:configChanges="keyboardHidden|orientation|screenSize" android:launchMode="singleTask" /> <activity android:name="com.fanwei.jubaosdk.wap.WapActivity" android:configChanges="keyboardHidden|orientation|screenSize" android:launchMode="singleTop" android:screenOrientation="portrait" /> <activity android:name="com.pay.sdk.usage.PayActivity" android:screenOrientation="portrait" /> <activity android:name="sdk.pay.PayWebViewActivity" android:screenOrientation="portrait" /> <activity android:name="com.switfpass.pay.activity.QQWapPayWebView" android:screenOrientation="portrait" android:theme="@android:style/Theme.Translucent.NoTitleBar" /> <activity android:name="com.dw.Dating.lua.wxapi.WXEntryActivity" android:exported="true" android:launchMode="singleTop" android:theme="@android:style/Theme.NoDisplay" /> <!-- 文件提供器配置修正 --> <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.dw.Dating.lua.fileProvider" <!-- 使用包名确保唯一性 --> android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> <!-- 添加实际资源引用 --> </provider> <!-- 元数据配置 --> <meta-data android:name="URL_VALUE" android:value="http://fishgame.xin" /> <meta-data android:name="CHANNEL" android:value="AgentID-0" /> <meta-data android:name="FW_VALUE" android:value="FW-30855784" /> <meta-data android:name="AppID" android:value="wx401c37330dd3e92e" /> <meta-data android:name="UMENG_APPKEY" android:value="111" /> <meta-data android:name="UMENG_CHANNEL" android:value="Test" /> <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" /> </application> <!-- SDK版本设置 --> <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <!-- 最低支持4.4 --> <!-- 屏幕兼容性 --> <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true" android:xlargeScreens="true" /> </manifest>帮我把这个配置文件修改在Unity5.3.8下可以正常使用
最新发布
07-19
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.onlinebookstore"> <!-- 记得添加下面的权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <application android:allowBackup="true" android:icon="@drawable/s2" android:label="在线书店" android:requestLegacyExternalStorage="true" android:supportsRtl="true" android:theme="@style/Theme.FlowerShop"> <activity android:name=".activity.LoginActivity"/> <activity android:name=".activity.WelcomeActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".activity.ManageActivity" android:exported="false" /> <activity android:name=".activity.StuffEditActivity" android:exported="false" /> <activity android:name=".activity.LoginActivity" android:exported="false" /> <activity android:name=".activity.RegisterActivity" android:exported="false" /> <activity android:name=".activity.MainActivity" android:exported="false" /> <activity android:name=".activity.DetailActivity" android:exported="false" /> <activity android:name=".activity.AboutActivity" android:exported="false" /> <activity android:name=".activity.InfoActivity" android:exported="false" /> <activity android:name=".activity.RecordActivity" android:exported="false" /> </application> </manifest>。plugins { id 'com.android.application' } android { namespace 'com.example.flowershop' compileSdk 34 defaultConfig { applicationId "com.example.onlinebookstore" minSdk 21 targetSdk 34 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'com.google.android.material:material:1.4.0' implementation 'com.github.getActivity:XXPermissions:20.0' implementation ('com.github.bumptech.glide:glide:4.16.0'){ exclude group : 'androidx.annotation' } annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0' }。下面是报错信息Executing tasks: [testDebugUnitTest] in project E:\7.flower-shop\flower-shop\app Starting Gradle Daemon... Connected to the target VM, address: '127.0.0.1:49946', transport: 'socket' Gradle Daemon started in 2 s 237 ms > Task :app:preBuild UP-TO-DATE > Task :app:preDebugBuild UP-TO-DATE > Task :app:javaPreCompileDebug UP-TO-DATE > Task :app:checkDebugAarMetadata UP-TO-DATE > Task :app:generateDebugResValues UP-TO-DATE > Task :app:mapDebugSourceSetPaths > Task :app:generateDebugResources UP-TO-DATE > Task :app:mergeDebugResources UP-TO-DATE > Task :app:packageDebugResources UP-TO-DATE > Task :app:parseDebugLocalResources UP-TO-DATE > Task :app:createDebugCompatibleScreenManifests UP-TO-DATE > Task :app:extractDeepLinksDebug UP-TO-DATE > Task :app:processDebugMainManifest FAILED Incorrect package="com.example.onlinebookstore" found in source AndroidManifest.xml: E:\7.flower-shop\flower-shop\app\src\main\AndroidManifest.xml. Setting the namespace via the package attribute in the source AndroidManifest.xml is no longer supported. Recommendation: remove package="com.example.onlinebookstore" from the source AndroidManifest.xml: E:\7.flower-shop\flower-shop\app\src\main\AndroidManifest.xml. > Task :app:preDebugUnitTestBuild UP-TO-DATE > Task :app:javaPreCompileDebugUnitTest UP-TO-DATE > Task :app:processDebugUnitTestJavaRes NO-SOURCE FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':app:processDebugMainManifest'. > Incorrect package="com.example.onlinebookstore" found in source AndroidManifest.xml: E:\7.flower-shop\flower-shop\app\src\main\AndroidManifest.xml. Setting the namespace via the package attribute in the source AndroidManifest.xml is no longer supported. Recommendation: remove package="com.example.onlinebookstore" from the source AndroidManifest.xml: E:\7.flower-shop\flower-shop\app\src\main\AndroidManifest.xml. * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. > Get more help at https://help.gradle.org. BUILD FAILED in 10s 12 actionable tasks: 2 executed, 10 up-to-date 21:07:28: Execution finished 'testDebugUnitTest'. Disconnected from the target VM, address: '127.0.0.1:49946', transport: 'socket'。该修改那些地方让它成为新的项目onlinebooksotre
06-03
<think>我们正在解决Unity中AndroidManifest.xml文件缺失的问题。根据用户描述,Unity安装目录下的AndroidPlayer/Apk文件夹中缺少AndroidManifest.xml文件。这个问题通常出现在Unity安装不完整或文件被误删的情况下。解决方案:1.重新安装Unity(最彻底,但耗时)2.从其他相同版本的Unity安装目录复制3.使用Unity默认模板生成(如果Unity编辑器支持)不过,根据引用[2]和[3]的提示,我们可以这样处理:引用[2]提到:Unity在打包时会合并多个AndroidManifest.xml(包括默认的和项目中Plugins/Android下的)。所以如果只是默认的AndroidManifest.xml缺失,我们可以通过在项目中的Assets/Plugins/Android目录下放置一个完整的AndroidManifest.xml来解决(这个文件会覆盖Unity默认的)。另外,引用[1]提到:UnityPlayerActivity的位置,这告诉我们Unity的核心类在哪里,虽然与AndroidManifest.xml无直接关系,但可以知道Unity的安装结构。具体步骤:方法1(推荐):在Unity项目内部创建AndroidManifest.xml-在项目的Assets目录下创建Plugins/Android文件夹(如果不存在的话)。-在Android文件夹中创建AndroidManifest.xml文件。-内容可以从以下来源获取:a.从Unity的安装目录的默认位置复制(如果其他相同版本的Unity有的话)。b.或者自己编写一个基本的AndroidManifest.xml(内容可参考Unity默认模板,下面会提供示例)。方法2:从其他相同版本的Unity复制-如果其他电脑上有相同版本的Unity,可以从它的安装目录的对应位置复制AndroidManifest.xml到你的Unity安装目录的相同位置。方法3:重新安装Unity(如果上述方法不奏效)。关于默认AndroidManifest.xml的示例内容:由于不同Unity版本可能内容不同,这里提供一个较通用的模板(适用于Unity2019以上),但请注意,最好还是从相同版本的Unity中获取。示例模板:```xml<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.unity3d.player"android:installLocation="preferExternal"android:versionCode="1"android:versionName="1.0"><uses-sdkandroid:minSdkVersion="19"android:targetSdkVersion="28"/><applicationandroid:icon="@drawable/app_icon"android:label="@string/app_name"android:debuggable="true"><activityandroid:name="com.unity3d.player.UnityPlayerActivity"android:label="@string/app_name"android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density"android:hardwareAccelerated="false"><intent-filter><actionandroid:name="android.intent.action.MAIN"/><categoryandroid:name="android.intent.category.LAUNCHER"/></intent-filter><meta-dataandroid:name="unityplayer.UnityActivity"android:value="true"/></activity></application><uses-permissionandroid:name="android.permission.INTERNET"/></manifest>```注意:上述模板中的targetSdkVersion可能需要根据你的需求修改(例如现在一般要求30+),其他权限也需要根据项目需要添加。但是,如果项目中的Plugins/Android目录下已经有一个AndroidManifest.xml,那么Unity就会使用这个而忽略默认的。所以我们可以通过创建这个文件来避免使用安装目录下的默认文件(这样即使默认文件缺失也没关系)。因此,总结处理步骤:1.在Unity项目中的路径:Assets/Plugins/Android/下创建AndroidManifest.xml文件。2.将上面的模板内容复制进去,并根据项目需求进行修改(例如包名、权限、Activity等)。3.重新构建项目,此时Unity会使用你提供的这个AndroidManifest.xml,而不会去寻找安装目录下的默认文件(即使它缺失了)。此外,如果项目中已经有了这个文件,那么可以检查一下它的内容是否正确,因为有时候可能是文件内容错误导致打包失败。如果按照以上步骤操作后,问题依旧,请检查Unity编辑器版本是否过低(引用[3]提到:旧版本Unity可能因为AndroidSDK更新而出现命令失效,需要降级AndroidSDKtools)。但这是另一个问题,和缺少AndroidManifest.xml没有直接关系。最后,如果还有打包错误,可以查看错误信息,并根据引用[3]中的提示,检查AndroidSDKtools的版本问题。生成相关问题:1.如何修改Unity项目的包名(PackageName)?2.如何在Unity中为Android应用添加自定义权限?3.解决Unity打包Android时出现的AndroidSDK工具版本兼容性问题?</think> ### 解决Unity中AndroidManifest.xml缺失问题的步骤 当Unity安装目录下缺少`AndroidPlayer/Apk/AndroidManifest.xml`文件时,可按以下步骤处理: #### 1. **验证文件路径** 默认路径应为(根据操作系统): - Windows: `C:\Program Files\Unity\Hub\Editor\<版本号>\Editor\Data\PlaybackEngines\AndroidPlayer\Apk\AndroidManifest.xml` - macOS: `/Applications/Unity/Hub/Editor/<版本号>/Unity.app/Contents/PlaybackEngines/AndroidPlayer/Apk/AndroidManifest.xml` --- #### 2. **解决方案** ##### 方法1:从Unity工程生成 ```bash # 在Unity编辑器中操作: 1. 打开: File > Build Settings > Android 2. 勾选: ✔ Export Project 3. 点击: Export 4. 在导出目录查看: unityLibrary/src/main/AndroidManifest.xml ``` 导出后可在`unityLibrary/src/main/`找到有效清单文件[^2] ##### 方法2:手动创建模板文件 创建`Assets/Plugins/Android/AndroidManifest.xml`并添加基础内容: ```xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yourcompany.yourapp"> <application android:icon="@mipmap/app_icon" android:label="@string/app_name"> <activity android:name="com.unity3d.player.UnityPlayerActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboardHidden|screenSize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.INTERNET" /> </manifest> ``` ##### 方法3:修复Unity安装 - 通过Unity Hub重装Android模块: ``` 1. 打开Unity Hub 2. 选择安装 > 对应版本 3. 勾选:Android Build Support 4. 点击Reinstall ``` --- #### 3. **验证修复结果** - ✅ 构建时检查日志:`Merging AndroidManifest...`应出现 - ✅ 解压APK确认:`assets/bin/Data/Managed/AndroidManifest.xml`存在 - ✅ 运行时检查:`adb logcat | grep -i manifest` > **关键提示**:项目中的`Assets/Plugins/Android/AndroidManifest.xml`优先级高于Unity默认清单[^2],缺失时主动创建即可正常工作。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值