赞
踩
Android开发工具箱大概在版本2.2.0(2021-06-10)就已经支持查看鸿蒙系统信息以及鸿蒙应用信息了。这里我讲一下Android开发工具箱是如何在Android应用中(APK)获取鸿蒙应用Ability信息(类似于Android应用的四大组件信息)
Android开发工具箱可在应用宝、酷安下载,微信公众号:Android开发工具箱
https://www.coolapk.com/apk/com.su.assistant.pro
Android中,我们获取应用列表之后,再获取应用的PackageInfo实例即可获得四大组件列表,在鸿蒙中,我们获取到通过IBundleManager获取到Ability列表即可。IBundleManager类似Android中的PackageManager,在Android中,我们通过Context即可获取PackageManager,在鸿蒙中,通过ohos.app.Context也同样可以得到IBundleManager。
鸿蒙中的ohos.app.Context从何处来,根据我的Android的开发经验,我首选Application。
鸿蒙系统中也有一个Application,此Application并非Android中的android.app.Application,而是ohos.app.Application
整理一下步骤,我将尝试依次获取如下类型的实例:
ohos.app.Application
ohos.app.Context
ohos.bundle.IBundleManager
我们知道在鸿蒙中有ohos.abilityshell.HarmonyApplication,它是继承android.app.Application,所以它只是一个Android中的普通的Application。HarmonyApplication源码是公开的,我在里面发现了这个:
private ohos.app.Application application = new ohos.app.Application();
但是,在Android系统中是没有这个东西的,所以我们无法直接的在Android系统get一个ohos.app.Application对象。不过,我们可以尝试构造一个ohos.app.Application对象。这里要注意的是,我们也没有办法直接引用这个类,因为鸿蒙并没有公开相应的代码,所以只有反射咯。
实例化Application很简单,就是调用一个无参的构造函数即可
- val applicationContext = context.applicationContext
- val classLoader = applicationContext.classLoader
- val clazzOhosApplication = Class.forName("ohos.app.Application")
- sOhosApplication = clazzOhosApplication.newInstance()
此时我们可以通过sOhosApplication利用反射拿到ohos.app.Context
可惜,事情到这里并没结束,我们通过ohos.app.Context获取IBundleManager依然返回null。我猜测是初始化ohos.app.Application的时候出了问题
接下来继续在HarmonyApplication里面找线索,由于里面用了很多闭源的类,所以在阅读的时候造成了很大障碍,最终,我在下面的函数中找到了线索
-
- private void attachHapModuleContext(AbilityContext harmonyAbilityPackage, HapModuleInfo hapModuleInfo) {
- if (harmonyAbilityPackage != null) {
- ContextDeal deal = new ContextDeal(getApplicationContext(), getClassLoader());
- ...
- deal.setApplication(this.application);
- ...
- }
- harmonyAbilityPackage.attachBaseContext(deal);
- }
为了方便阅读,我把无关的代码删除了。上面if中的逻辑和初始化ohos.app.Application是相关的,所以利用反射复制一遍上述代码的逻辑
- private fun initApplication(context: Context) {
- val applicationContext = context.applicationContext
- val classLoader = applicationContext.classLoader
- try {
- val clazzOhosApplication = Class.forName("ohos.app.Application")
- sOhosApplication = clazzOhosApplication.newInstance()
- val clazzContextDeal = Class.forName("ohos.app.ContextDeal")
- val contextDealConstructor = clazzContextDeal.getConstructor(
- Context::class.java, ClassLoader::class.java
- )
- val contextDeal = contextDealConstructor.newInstance(applicationContext, classLoader)
- val setApplicationMethod =
- clazzContextDeal.getDeclaredMethod("setApplication", clazzOhosApplication)
- setApplicationMethod.invoke(contextDeal, sOhosApplication)
- } catch (e: Throwable) {
- Log.w(TAG, e)
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
然后再次运行,遗憾的是,此时我们通过ohos.app.Context获取IBundleManager依然返回null。
在attachHapModuleContext方法中的最后执行了AbilityContext.attachBaseContext(ContextDeal),可惜AbilityContext也没有开源,我们无法知道AbilityContext.attachBaseContext(ContextDeal)里面做了什么。
不过,我发现ohos.app.Application是继承AbilityContext的(反射打印一下便知),将上面的代码修改一下,调用一下attachBaseContext
- private fun initApplication(context: Context) {
- val applicationContext = context.applicationContext
- val classLoader = applicationContext.classLoader
- try {
- val clazzOhosApplication = Class.forName("ohos.app.Application")
- sOhosApplication = clazzOhosApplication.newInstance()
- LogUtil.logParents(clazzOhosApplication)
- LogUtil.logClassMethods(clazzOhosApplication)
- val clazzContextDeal = Class.forName("ohos.app.ContextDeal")
- val contextDealConstructor = clazzContextDeal.getConstructor(
- Context::class.java, ClassLoader::class.java
- )
- val contextDeal = contextDealConstructor.newInstance(applicationContext, classLoader)
- val setApplicationMethod =
- clazzContextDeal.getDeclaredMethod("setApplication", clazzOhosApplication)
- setApplicationMethod.invoke(contextDeal, sOhosApplication)
- val attachBaseContextMethod =
- clazzOhosApplication.getMethod("attachBaseContext", ohos.app.Context::class.java)
- attachBaseContextMethod.invoke(sOhosApplication, contextDeal)
- } catch (e: Throwable) {
- Log.w(TAG, e)
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
再次尝试获取IBundleManager,这次终于成功了,我们有了IBundleManager实例。
在Android中,我们获取四大组件信息就要先获得PackageInfo,然后再获取组件信息
- packageInfo.activities
- packageInfo.receivers
- packageInfo.services
- packageInfo.providers
在鸿蒙中,我们获取BundleInfo,从BundleInfo中可直接获得AbilityInfo,但是要注意的是,只有鸿蒙应用才有bundleInfo,鸿蒙系统安装apk文件是没有bundleInfo的,返回结果为null
- fun getBundleInfo(bundleName: String, flags: Int): BundleInfo? {
- try {
- return mIBundleManager!!.getBundleInfo(bundleName, flags)
- } catch (e: RemoteException) {
- Log.w("IBundleManagerDelegate", "bundleName: $bundleName", e)
- }
- return null
- }
为了方便大家测试,这里告诉大家华为远程模拟器P40中
com.huawei.email是鸿蒙应用
com.sina.weibo是Android应用(可在华为市场下载鸿蒙版微博)
然后,程序又挂了...我们还需要一个权限:
-
- <uses-permission android:name="ohos.permission.GET_BUNDLE_INFO" />
接下来再获取BundleInfo就可正常获取了
ohosContext!!.bundleManager!!.getBundleInfo(bundleName, flags)
想要查看鸿蒙系统中哪些是鸿蒙应用,可以使用Android开发工具箱的应用统计功能(PRO),其中一项为应用类型统计。
鸿蒙应用中所有组件信息都为AbilityInfo类型,通过type(AbilityInfo.AbilityType)来区分组件类别。至此,我们拿到了AbilityInfo实例,也就是拿到了组件所有信息了。
获取系统信息就简单了,下面是获取版本信息
-
- SystemVersion.getVersion()
SystemVersion还可以获取其他信息,这里就不再列举了
最后,我将此部分代码贡献给了开源应用LibChecker - https://github.com/zhaobozhen/LibChecker
LibChecker是一个查看并分析App使用的第三方库的应用。提供了一些基本功能:App的ABI架构查看和统计、原生库的查看、四大组件查看,除此之外还对知名库进行标记、统计等。也欢迎大家试用
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。