前言
使用appium做安卓app的自动化,第一件事儿就是启动一个activity(也就是页面)。一个app里有那么多页面,如果我想测试哪个页面就直接启动哪个页面该多好。但事实是,一个应用市场包中(非debug包),只有很少的页面可以被外部应用(另一个进程,比如appium)直接启动。所以在自动化脚本中,你只能先启动主页面,然后一步一步的走到被测试页面。那么问题来了,到底哪些activity可以直接被appium启动呢?
答案在manifest.xml文件中找,规则就2条,非常简单。
规则1,先看Activity 的 android:exported
属性
在 AndroidManifest.xml
中,每个 <activity>
标签的 android:exported
属性决定了该 Activity 是否允许被外部组件(如 Appium)启动:
android:exported="true"
:允许外部启动。android:exported="false"
:仅允许同一应用或特权进程启动。
规则2,未显式设置 exported
属性的,看有没有 <intent-filter>
- 如果该 Activity 声明了
<intent-filter>
,则默认exported=true
。 - 如果没有
<intent-filter>
,则默认exported=false
。
举个栗子
<!-- 允许外部启动(显式或隐式) -->
<activity android:name=".MainActivity" 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=".InternalActivity" android:exported="false" />
<!-- 默认允许外部启动(因有intent-filter) -->
<activity android:name=".WebActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="https" />
</intent-filter>
</activity>
如何启动
声明了android:exported=”true”的Activity,可以通过Activity 的完整组件名(包名 + 类名)启动。(所谓的显示启动)
# Python + Appium 示例,显式启动Activity
driver.start_activity(app_package="com.example.pkg", app_activity=".MainActivity")
没声明exported=true,但声明了 <intent-filter>
的Activity,可以通过Intent 的 action
或 data
启动(所谓的隐式启动)
# Python + Appium 示例,启动系统浏览器打开网页(隐式Intent)
driver.execute_script('mobile: startActivity', {
'action': 'android.intent.action.VIEW',
'data': 'https://example.com'
})
为什么我作为一个APP要允许别的APP打开我的页面
- 分享
- 支付
为什么需要隐式启动?
- 解耦调用方与被调用方:调用方无需知道具体实现类的包名,只需声明意图(如“分享”)。
- 多应用竞争:多个应用可以注册同一 Intent 过滤器,用户可自由选择默认应用。(你最常见的下图,就是隐式启动的效果)
appium为什么不能想启动哪个就启动哪个Activity