如何判断Android应用运行在鸿蒙系统上

「椎锋陷陈」微信技术号现已开通,为了获得第一手的技术文章推送,欢迎搜索关注!

前言

不久前,HarmonyOS 2.0的正式发布,在华为用户及科技产品爱好者之间掀起了不小的波澜。其中,讨论关于HarmonyOS是如何兼容Android应用的话题最为频繁,从而引发了多方阵营关于「HarmonyOS究竟是否是套壳Android」的激烈争论。

与此同时,部分嗅到风向的开发者,已经在部署如何收集应用在HarmonyOS上的兼容情况了。这不,笔者所在的公司就安排我去进行相关的技术调研。其中,最重要的一点就是判断当前应用是否搭载在了HarmonyOS上,从而统计升级HarmonyOS的用户数量,作为后续公司战略方向可能调整的依据。

OpenHarmony与HarmonyOS

首先,让我们先为前面的争论下一个明确的定论,即:

HarmonyOS并非套壳Android。

我们通常意义上所讲的HarmonyOS,实际分成了两部分,一部分是 OpenHarmony,另一部分则是包括HMS在内的闭源应用与服务。

OpenHarmony是由开放原子开源基金会孵化及运营的开源项目,其性质与定位可参照Android开放源代码项目(AOSP) 。

而HarmonyOS 2.0则是华为基于OpenHarmony 2.0开发的面向多种全场景智能设备的商用版本。HarmonyOS 2.0遵循了AOSP的开源许可,从而实现了现有Android生态应用在部分搭载HarmonyOS 2.0的设备上的正常运行。

目前在HarmonyOS 2.0上存在两种类型的应用,即

  • 纯HarmonyOS应用(指基于HarmonyOS开发的应用,不能安装在其他Android手机上,应用体积很小,但同时功能也很少)
  • 支持HarmonyOS特性的应用(基于Android开发的应用,但是使用了 HarmonyOS的特性,通过工具导出时后缀仍然是APK)

HarmonyOS检测方法

现在回到我们最初的需求,即基于Android开发的应用,该如何判断是否是搭载在了HarmonyOS上呢?

对于这个问题的我的第一个解决思路就是:

通过读取Android系统配置,遍历能够作为判断依据的属性

Android系统配置介绍

为了让所有运行中的进程共享系统运行时所需要的各种属性值,Android系统开辟了属性存储区域,并提供了访问该区域的API。属性由键(key)与值(value)构成,两者都是字符串类型。

属性被大量使用在Android系统中,用来记录系统设置或进程之间的信息交换。属性是在整个系统中全局可见的。每个进程可以get/set属性。

我们可以通过以下两种方式访问到系统配置中的属性值:

adb命令行工具
  • adb shell getprop 可以查看手机上所有属性值。
  • abb shell getprop xxx 可以查看某个指定属性值。

1.png

SystemProperties类

Systemproperties类在android.os目录下,但这个类是被标记为隐藏的,上层应用开发无法直接使用,但我们可以用反射的方式调用。创建/修改属性可以用Systemproperties.set(property,value)方法,获取属性则可以用Systemproperties.get(property)方法。

比如,我们可以通过此方式获取设置-关于手机中显示的版本号:

/**
 * 获取鸿蒙系统版本号
 */
fun getHarmonyOsVersion(): String {
    return if (isHuaweiBrand() && isHarmonyOs()) {
        try {
            val cls = Class.forName("android.os.SystemProperties")
            val method = cls.getMethod("get", String::class.java)
            method.invoke(cls, "ro.huawei.build.display.id") as String
        } catch (e: Exception) {
            "-1"
        }
    } else {
        "-1"
    }
}

当然,这个版本号可以用一种更直接的方式获取:

/**
 * 获取鸿蒙系统版本号
 */
fun getHarmonyOsVersion(): String {
    return if (isHuaweiBrand() && isHarmonyOs()) {
        Build.DISPLAY
    } else {
        "-1"
    }
}

通过阅读源码我们可以得知,其真正的实现也是通过调用SystemProperties.get(property)进行的,底层通过jni调用native方法实现属性的存取:

    public static final String DISPLAY = getString("ro.build.display.id");
    
    private static String getString(String property) {
        return SystemProperties.get(property, UNKNOWN);
    }
    
    public static String get(@NonNull String key, @Nullable String def) {
        if (TRACK_KEY_ACCESS) onKeyAccess(key);
        return native_get(key, def);
    }

但是很遗憾,遍历了所有的属性值之后,发现跟OS相关的属性值仍是关联到Android系统的,唯一出现Harmony字样的,是一个默认来电铃声的属性值:

4.png

所以,想要以此方案作为判断依据,我们需要通过读取默认来电铃声属性值并判断是否以Harmony结尾,但由于目前我手头上只有一台升级到HarmonyOS 2.0的手机,无法确保在其他机型的手机上该属性值也一致,因此只能将此方案作为保留方案。

另外一个解决思路则是:

通过是否支持调用HarmonyOS Java API来判断

至于调用方式,和你猜想的一样,依然是以反射的形式,看看能否在运行时获取相关API的类的Class对象。

在HarmonyOS开发者官网上可以看到,最新发布的HarmonyOS SDK Release版的版本号是2.1.1.21,API版本为5(截至2021.6.22)。

2.png

而在HarmonyOS Java API文档中通过Since来标记包、类或接口等开始支持的版本号,如“Since:1”表示从API Version 1开始支持。

于是我们选择最新的API版本为5的类来作为试验对象:

3.png

具体代码也很简单,使用Class类的forName静态方法,以完整类名为参数获取Class对象,如果Class对象不为空,即可证明当前应用搭载在了HarmonyOS上:

/**
 * 当前是否是鸿蒙系统
 * 根据是否能调用Harmony JAVA API判断
 */
fun isHarmonyOs(): Boolean {
    return try {
        val cls = Class.forName("ohos.utils.system.SystemCapability")
        cls != null
    } catch (e: Exception) {
        false
    }
}

一点小疑惑

我为什么要选择API版本为5的类来判断呢?这是因为,通过是否支持调用HarmonyOS Java API来判断应用搭载在HarmonyOS的设备上这种思路,其实我一开始就想到了,但我最初是选用了HarmonyOS开发者官网第一个介绍的特性——Ability相关的类,而该类的API版本为1。

测试发现,升级了HarmonyOS和未升级的手机上居然都能够获取到Ability的Class对象!!!

百思不得其解的我,直到在查阅了HarmonyOS的历史版本说明后才注意到以下这一句:

5.png

于是进一步在HarmonyOS开发者的官方公众号上确认,得到了以下回复:

6.jpg

因此证明,通过是否支持调用HarmonyOS Java API来判断应用搭载在HarmonyOS的设备上这种思路是正确的,但要选用API版本为5的类才可以。

但是另外一个疑惑又产生了,即未升级HarmonyOS的手机为什么也能调用API版本低于5以下的HarmonyOS Java API呢?难道HarmonyOS的一部分特性相关的库早就在现有华为手机的EMUI上部署了吗?此问题目前还得不到合理的解释。

总结

为了减少用户的迁移成本,保护用户的现有数据,现阶段的HarmonyOS选择了在遵循AOSP的开源许可基础上兼容Android生态应用。

也是由于这一点,加上华为开发者官网上并没有明确给出API,导致基于Android开发的应用,要判断是否搭载在HarmonyOS上会比较迂回。

目前比较可靠的方式,是通过是否支持调用HarmonyOS Java API来判断,并且必须选择API版本为5的类。

如果你有更好的方式,欢迎在文章下方留言告诉我,谢谢~

「椎锋陷陈」微信技术号现已开通,为了获得第一手的技术文章推送,欢迎搜索关注!

参考

OpenHarmony和HarmonyOS有什么区别?
https://developer.huawei.com/consumer/cn/forum/topic/0202596835671930522?fid=0101303901040230869

HarmonyOS Java API参考
https://developer.harmonyos.com/cn/docs/documentation/doc-references/systemversion-0000001054358980#ZH-CN_TOPIC_0000001054358980__getReleaseType–

Android 系统属性SystemProperty分析
https://blog.youkuaiyun.com/yangwen123/article/details/8936555

<think> 嗯,用户询问的是如何在鸿蒙Next系统上解决Android MediaProjection录屏功能无法运行的问题。首先需要理解鸿蒙Next与安卓的兼容性变化。根据引用[3]和[4],鸿蒙Next已不再兼容安卓APK文件,这意味着直接运行安卓应用会遇到问题。 接着思考MediaProjection的具体情况。这个API属于安卓系统级功能,依赖AOSP底层服务。而鸿蒙Next作为独立系统,其架构和接口必然与安卓不同。因此,原生安卓的MediaProjection无法在鸿蒙Next上运行是系统架构差异导致的必然结果。 那么解决方案应该从鸿蒙原生开发入手。查过资料后,发现鸿蒙的录屏功能主要通过AVRecorder和AVCapture实现。前者用于录制媒体文件,后者适合实时处理帧数据。需要向用户明确说明这种底层差异,并提供具体的代码示例。 考虑到用户可能是开发者,应该提供详细的开发指导。比如使用AVRecorder时需要声明权限、配置参数、实现回调等步骤。对于需要实时处理的场景,则要介绍AVCapture的用法,包括获取surface和传输帧数据的流程。 另外注意到用户提到"无法正常运行",可能需要区分两种情况:如果是想直接运行安卓录屏应用,那基本不可行;如果是开发鸿蒙应用时遇到问题,则需要更深入的技术支持。在回答中应该涵盖这两种情况。 最后要提醒替代方案的重要性。比如如果用户需要临时解决方案,可以建议使用系统内置录屏功能,或通过PC投屏工具。但长期来看,迁移到鸿蒙原生开发才是根本解决之道。 </think> 鸿蒙Next系统(HarmonyOS NEXT)已**不再兼容安卓应用和安卓API**,包括`MediaProjection`录屏功能。这是系统架构的根本变化(纯血鸿蒙),直接运行或调用安卓APK中的API(如`MediaProjection`)**已不可行**[^3][^4]。 --- ### 🔧 解决方案:迁移到鸿蒙原生开发 要在鸿蒙Next上实现录屏功能,**必须使用鸿蒙原生API开发**。主要方案如下: #### ✅ 方案一:使用鸿蒙`AVRecorder`(推荐) 鸿蒙的`@ohos.multimedia.media`库提供原生录屏API: ```typescript import media from '@ohos.multimedia.media'; import window from '@ohos.window'; // 1. 获取屏幕Surface let screenSurface: Promise<media.Surface> = window.getLastWindow(context).then(window => { return window.createSurface("screen_capture"); }); // 2. 配置录屏参数 let avConfig: media.AVRecorderConfig = { audioSourceType: media.AudioSourceType.AUDIO_SOURCE_MIC, // 麦克风 videoSourceType: media.VideoSourceType.VIDEO_SOURCE_SURFACE, // 屏幕Surface profile: { audioBitrate: 48000, audioChannels: 2, audioCodec: media.CodecMimeType.AUDIO_AAC, audioSampleRate: 48000, fileFormat: media.ContainerFormatType.CFT_MPEG_4, videoBitrate: 2000000, videoCodec: media.CodecMimeType.VIDEO_AVC, videoFrameWidth: 1080, // 分辨率 videoFrameHeight: 1920, videoFrameRate: 30 // 帧率 }, url: 'file:///data/storage/el2/base/cache/screen_record.mp4' // 存储路径 }; // 3. 创建录制器并开始录屏 let avRecorder: media.AVRecorder; media.createAVRecorder().then((recorder) => { avRecorder = recorder; return avRecorder.prepare(avConfig); }).then(() => { return screenSurface.then(surface => { return avRecorder.getInputSurface().then(surface => { return avRecorder.start(); // 开始录制 }); }); }).catch((error) => { console.error(`录屏启动失败: ${error.code}, ${error.message}`); }); ``` #### ✅ 方案二:使用`AVCapture`(需实时处理帧) 若需逐帧处理屏幕数据(如直播推流),使用`@ohos.multimedia.avcapture`: ```typescript import avCapture from '@ohos.multimedia.avcapture'; // 1. 创建屏幕捕获会话 let captureSession: avCapture.CaptureSession; avCapture.createCaptureSession(context).then((session) => { captureSession = session; // 2. 添加屏幕输入源 return avCapture.createScreenCaptureSource(session); }).then((screenInput) => { // 3. 配置输出(如文件或预览) let profile: avCapture.VideoProfile = { size: { width: 1080, height: 1920 }, frameRate: 30 }; let videoOutput = await avCapture.createVideoOutput(context, profile); captureSession.addOutput(videoOutput); // 4. 启动录屏 return captureSession.start(); }).catch((error) => { console.error(`屏幕捕获失败: ${error.code}`); }); ``` --- ### ⚠️ 关键注意事项 1. **权限声明** 在`module.json5`中声明必要权限: ```json "requestPermissions": [ { "name": "ohos.permission.MEDIA_LOCATION", // 媒体位置 "reason": "录制屏幕需要存储视频" }, { "name": "ohos.permission.CAPTURE_SCREEN" // 截屏录屏权限 } ] ``` 2. **兼容性适配** - 仅HarmonyOS NEXT 4.0+支持完整API - 旧版鸿蒙设备(保留AOSP兼容层)可能仍支持`MediaProjection`[^4],但新设备必须用原生方案 3. **替代方案** *临时需求*可考虑: - 使用系统自带录屏功能(下拉控制中心快捷操作) - 通过PC端投屏工具(如华为多屏协同)录制 --- ### 💎 总结 | **场景** | **解决方案** | |-----------------------------|---------------------------------| | 运行安卓录屏APP | ❌ 鸿蒙Next不再支持 | | 开发鸿蒙原生录屏功能 | ✅ `AVRecorder`或`AVCapture` | | 旧鸿蒙设备(非NEXT) | ⚠️ 可能兼容`MediaProjection`[^4] | **根本解决路径是迁移到鸿蒙原生开发**。开发者需参考华为官方[多媒体开发指南](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/avsession-overview-0000001774120918)重构应用逻辑,彻底放弃对安卓API的依赖[^2][^3]。 --- ### ❓相关问题 1. 鸿蒙Next的`AVRecorder`与安卓`MediaProjection`在性能上有何差异? 2. 如何实现在鸿蒙录屏过程中叠加摄像头画面? 3. 鸿蒙原生录屏是否支持录制系统内部音频? 4. 从安卓`MediaProjection`迁移到鸿蒙API需要重写多少代码? 5. 鸿蒙Next对屏幕录制的隐私保护机制是怎样的? [^1]: 鸿蒙next系统以后会取代安卓吗? [^2]: 鸿蒙 NEXT (一)初识鸿蒙 [^3]: 纯鸿蒙!华为HarmonyOS NEXT不再兼容安卓应用 [^4]: 鸿蒙NEXT是否支持安卓
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值