在APK中获取鸿蒙应用Ability信息

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

整理一下步骤,我将尝试依次获取如下类型的实例:

  1. ohos.app.Application

  2. ohos.app.Context

  3. 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)
    }
}

然后再次运行,遗憾的是,此时我们通过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)
    }
}

再次尝试获取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中

  1. com.huawei.email是鸿蒙应用

  2. 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架构查看和统计、原生库的查看、四大组件查看,除此之外还对知名库进行标记、统计等。也欢迎大家试用

鸿蒙应用技术记账簿App程序是基于华为鸿蒙操作系统开发的一款个人财务管理应用。通过使用华为提供的DevEco Studio开发工具,开发者可以快速构建和调试鸿蒙应用。以下是开发记账簿App程序的一些关键步骤和要点: ### 开发环境搭建 1. **下载安装DevEco Studio**:首先需要在华为开发者网站上下载并安装DevEco Studio开发工具。 2. **配置开发环境**:安装完成后,需要配置JDK、Android SDK等开发环境。 ### 创建新项目 1. **启动DevEco Studio**:打开DevEco Studio,选择“Create New Project”。 2. **选择模板**:在模板选择界面,选择适合的模板,例如“Empty Ability”或“Basic Ability”。 3. **配置项目信息**:填写项目名称、包名、保存路径等信息,然后点击“Finish”创建项目。 ### 设计用户界面 1. **使用XML布局文件**:在`resources/base/layout`目录下创建布局文件,使用XML语言设计用户界面。 2. **预览界面**:在DevEco Studio中使用预览功能查看界面效果,确保布局符合预期。 ### 编写业务逻辑 1. **创建Ability**:在`src/main/java`目录下创建Ability类,处理用户交互和业务逻辑。 2. **数据存储**:使用鸿蒙提供的存储API(如分布式数据对象)来保存和管理记账数据。 3. **网络请求**:如果需要从网络获取数据,可以使用鸿蒙的网络请求API。 ### 测试与调试 1. **使用模拟器**:在DevEco Studio中使用模拟器测试应用功能。 2. **真机调试**:将应用部署到鸿蒙设备上进行真机调试,确保应用在真实环境中的表现。 ### 发布应用 1. **生成签名文件**:在DevEco Studio中生成签名文件,用于应用签名。 2. **构建发布版本**:选择“Build > Build APK(s)”生成发布版本的应用包。 3. **上传到应用商店**:将应用包上传到华为应用商店进行审核和发布。 ### 示例代码 以下是一个简单的记账簿App的示例代码,展示如何创建Ability和保存数据: ```java import ohos.aafwk.ability.Ability; import ohos.aafwk.content.Intent; import ohos.data.distributed.common.*; import ohos.rpc.*; public class AccountBookAbility extends Ability { private DistributedDataHelper dataHelper; @Override public void onStart(Intent intent) { super.onStart(intent); dataHelper = new DistributedDataHelper(getContext()); } public void addTransaction(String description, double amount) { dataHelper.saveTransaction(description, amount); } public void getTransactions() { dataHelper.getAllTransactions(); } } class DistributedDataHelper { private DistributedData data; public DistributedDataHelper(Context context) { data = new DistributedData(context); } public void saveTransaction(String description, double amount) { data.put(description, amount); data.flush(); } public List<Transaction> getAllTransactions() { List<Transaction> transactions = new ArrayList<>(); Map<String, Double> dataMap = data.getAll(); for (Map.Entry<String, Double> entry : dataMap.entrySet()) { transactions.add(new Transaction(entry.getKey(), entry.getValue())); } return transactions; } } class Transaction { private String description; private double amount; public Transaction(String description, double amount) { this.description = description; this.amount = amount; } // Getters and setters } ``` ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值