当前位置:首页 » APP上架 » 正文

小米开发平台Activity Embedding 适配指南

小米开发平台Activity Embedding 适配指南

1、功能介绍

为了利用大屏幕的显示区域,GoogleJetpack WindowManager中添加了Activity Embedding,实现同一应用内不同activity分屏显示,开发者可以通过配置XML文件或者进行Jectpack WindowManager API调用确定如何显示activity(并排或堆叠)。

目前支持以下两种逻辑跳转,第一种是可以实现左容器界面固定:

小米开发平台Activity Embedding 适配指南小米开发平台Activity Embedding 适配指南

第二种是支持多层次导航:

小米开发平台Activity Embedding 适配指南小米开发平台Activity Embedding 适配指南

另外系统会自动维护对小屏幕的显示,当应用在小屏幕的设备上时,activity会相互堆叠,在大屏幕上,activity会并排显示,对于折叠屏,会随着设备折叠和展开而堆叠和并排显示activity。

小米开发平台Activity Embedding 适配指南小米开发平台Activity Embedding 适配指南

2、快速上手

JetPack WindowManager库添加了ActivityEmbeddingComponent,可以根据分屏规则创建容器实现应用内分屏,配置分屏规则涉及到下面几个步骤:

2.1 添加依赖项

将WindowManager库依赖项添加到应用的build.gradle文件中

implementation("androidx.window:window:1.1.0-alpha02")

2.2 配置分屏规则

2.2.1 XML静态配置

放在res资源文件的xml文件夹下

    <!-- The split configuration for activities. -->
    
    <resources
      xmlns:window="http://schemas.android.com/apk/res-auto">
      <!-- Automatically split the following activity pairs. -->
      <SplitPairRule
        window:clearTop="true"
        window:splitMinWidth="600dp">
        <SplitPairFilter
          window:primaryActivityName=".SplitActivityList"
          window:secondaryActivityName=".*"/>
      </SplitPairRule>
    
      <!-- Automatically launch a placeholder for the list activity. -->
    
      <SplitPlaceholderRule
        window:placeholderActivityName=".SplitActivityListPlaceholder"
        window:splitRatio="0.3"
        window:splitMinWidth="600dp">
        <ActivityFilter
          window:activityName=".SplitActivityList"/>
      </SplitPlaceholderRule>    
      
    <!-- Automatically launch a full activity. -->
    
    <ActivityRule window:alwaysExpand="true">
        <ActivityFilter 
            window:activityName=".FullActivity"/>
    </ActivityRule>
    
    </resources>

2.2.2 代码动态配置

运行时定义分屏的配置,开发者可以在startActivity或者onCreate时使用

splitController.registerRule(new SplitPairRule(newFilters));

splitController.unRegisterRule(new SplitPairRule(newFilters));

来动态添加/移除规则

protected void onCreate(@Nullable Bundle savedInstanceState) {
    Set<SplitPairFilter> pairFilters = new HashSet<>();
    SplitPairFilter filter = new SplitPairFilter(primaryActivityComponetName, 
            secondaryActivityComponetName, 
            null);
    pairFilters.add(filter);
    SplitPairRule pairRule = new SplitPairRule(pairFilters, 
            SplitRule.FINISH_ADJACENT, 
            SplitRule.FINISH_ALWAYS, 
            true, 
            600, 
            600, 
            0.3f, 
            LayoutDirection.LOCALE);
    SplitController splitController = SplitController.getInstance();
    splitController.registerRule(pairRule);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

2.3 将规则定义通知库

使用Jetpack Startup库在加载应用的其他组件和启动 activity 之前执行初始化。如需启用启动功能,请在应用的 build 文件中添加库依赖项:

implementation("androidx.startup:startup-runtime:1.1.0")

并在manifest中添加:

<!-- AndroidManifest.xml -->
<provider android:name="androidx.startup.InitializationProvider"
  android:authorities="${applicationId}.androidx-startup"
  android:exported="false"
  tools:node="merge">
  <!-- This entry makes ExampleWindowInitializer discoverable. -->
  <meta-data android:name="**androidx.window.sample.embedding.ExampleWindowInitializer**"
    android:value="androidx.startup" />
</provider>

2.4 添加初始化程序类实现

通过将包含定义 (main_split_config) 的 xml 资源文件的 ID 提供给 SplitController.initialize() 来设置规则:

class ExampleWindowInitializer extends Initializer<SplitController> {

  @Over网页一键生成appride
  SplitController create(Context context) {
    SplitController.initialize(context, R.xml.main_split_config);
    return SplitController.getInstance(context);
  }

  @Override
  List<Class<? extends Initializer<?>>> dependencies() {
    return emptyList();
  }

}

2.5 XML配置文件参数解析

参数 含义
SplitPairRule 分屏配对情景(两侧容器均有具体activity),对应SplitPairFilter
splitRatio 分屏比默认为0.5f,即左右5:5分屏 ,对于IM类应用,可考虑设置分屏比为0.3f,即左右3:7分屏
splitMinWidth 默认配置600dp,宽度达到600dp才可以分屏,主窗口可分屏显示的最小窗口宽度
splitMinSmallestWidth 默认配置600dp,主窗口可分屏显示的最小sw值
finishPrimaryWithSecondary 默认为  false,true:若secondary container中所有activity都finish,则primary container中创建分屏的activity也会finish,不推荐应用主动配置此项。(androidx.window:window:1.1.0-alpha03中默认是SplitRule.FINISH_ADJACENT)
finishSecondaryWithPrimary 默认为 ture, true:若primary container中所有activity都finish,则secondary container中所有activity也会finish,不推荐应用主动配置此项。(androidx.window:window:1.1.0-alpha03中默认是SplitRule.FINISH_ALWAYS)
clearTop 默认为 false,true:启动activity窗口分屏,存在相同的primary container,若新建secondary container,则原secondary container中的activity会被finish掉,推荐应用配置,避免右分屏出现多实例
SplitPairFilter 分屏配对关系(必需配置)
primaryActivityName 分屏的primay activity component name
secondaryActivityName 分屏的secondary activity component name
secondaryActivityAction 分屏的secondary activity 启动的action (配置此项需要在启动的时候添加action) 
参数 含义
SplitPlaceholderRule 用来描述分屏下的占位,对应ActivityFilter(必需配置)
placeholderActivityIntentName 通过同时打开两个activity创建分屏,secondary占位activity component name
componentName 组件名
intentAction intent
splitRatio 分屏比默认为0.5f,即左右5:5分屏
splitMinWidth 默认配置600dp,宽度达到600dp才可以分屏主窗口可分屏显示的最小窗口宽度
splitMinSmallestWidth 默认配置600dp,主窗口可分屏显示的最小sw值
ActivityFilter 适配占位规则的activity(必需配置)
参数 含义
ActivityRule 需要全屏显示的activity,对应ActivityFilter(必需配置
alwaysExpand 取值”true”或false true:启动的activity全屏显示
componentName 组件名
intentAction intent
ActivityFilter 适配全屏规则的activity(必需配置)

2.6 应用主动适配生效

2.6.1 MIUI meta-data标记

AndroidManifest.xml中声明下列meta-data字段。设置为true表示app已经主动适配,系统不会反向适配

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
    <meta-data android:name="embedded" android:value="true"/>
</application>

注意:

Android 13后该meta-data将不使用

2.6.2 Google property标记

Google官方添加property字段,用来标识APP是否允许系统反向适配Activity Embedding

true表示允许系统反向适配,false不允许系统反向适配

注意:自适配Activity Embedding和不允许系统反向适配Activity Embedding的APP需要设置为false

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
    <property 
        android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE" 
 app打包工具       android:value="false" />
</applicatio

3、适配指导

3.1 关于应用横竖屏

3.1.1 PAD 竖屏下进入ActivityEmbedding

平板设备处于竖屏状态时,我们推荐应用采用左下图的全屏显示样式,而不是进入ActivityEmbedding。竖屏下的左右分屏显示会导致信息量过多,难以聚焦。如果您的应用在竖屏下进入了ActivityEmbedding,原因是:应用设置的进入ActivityEmbedding的阈值splitMinWidth过小

小米开发平台Activity Embedding 适配指南小米开发平台Activity Embedding 适配指南
  • 获取屏幕大小

R版本之前:Display.getRealSize()、Display.getRealMetrics()。

R版本之后:WindowManager.getMaximumWindowMetrics() 。Jetpack WindowManager中支持使用WindowMetrics maximumWindowMetrics = WindowMetricsCalculator.

getOrCreate().computeMaximumWindowMetrics(activity);

  • 获取当前窗口大小

R版本之前: Display.getSize() 。

R版本之后:WindowManager.getCurrentWindowMetrics() 。Jetpack WindowManager中支持使用WindowMetrics maximumWindowMetrics = WindowMetricsCalculator.

getOrCreate(). computeCurrentWindowMetrics(activity);

推荐解决方案:开发者根据不同屏幕大小的设备动态计算进入分屏的阈值。可使用如下计算方式:

// 获取屏幕大小
WindowMetrics currentWindowMetrics = WindowMetricsCalculator.getOrCreate().
        computeCurrentWindowMetrics(activity);
// 获取当前窗口大小
WindowMetrics maximumWindowMetrics = WindowMetricsCalculator.getOrCreate().
        computeMaximumWindowMetrics(activity);
// 通过configuration获取desity
float density = (float) activity.getResources().getConfiguration().densityDpi / 160f;
// 根据屏幕大小动态设置window:splitMinWidth="600dp"大小,控制竖屏下不进ActivtiyEmbedding
// 为了保证折叠屏外屏下不进入ActivityEmbedding,需要设置一下splitMinSmallestWidth的值,默认600dp
int splitMinWidth = (int) (Math.min(maximumWindowMetrics.getBounds().width(), 
        maximumWindowMetrics.getBounds().height()) / density + 1);

3.1.2 PAD无法横屏

原因:ActivityEmbedding 只是改变activity的显示位置,不会强制更改方向,需要app支持横屏

推荐方案:第一个启动的activity方向设置为behind以及全屏启动的activity设置为behind

3.1.3 折叠屏控制在外屏竖屏显示

为了避免您适配ActivityEmbedding后在折叠屏外屏出现如下图所示的情况,需要控制应用在折叠屏外屏竖屏显示,监听 WindowInfoTracker 来手动设置方向,具体使用参考官方文档https://developer.android.com/guide/topics/large-screens/make-apps-fold-aware

小米开发平台Activity Embedding 适配指南小米开发平台Activity Embedding 适配指南

3.2 支持resizeable

应用需要在 AndroidManifest.xml 文件的 application 或者 actvivity 标签中添加 resizeableActivity=true 的属性。

若配置android:resizeableActivity=“false”,会导致无法分屏显示

<application
    android:resizeableActivity="true">
    <activity
          android:resizeableActivity="true" />
</application>

3.3 关于Configuration

当应用在折叠屏内外屏或平板横竖屏交替使用时,activity的大小会发生变化,我们强烈推荐Activity在大小切换时不重启来保证良好的连续性体验,遵循google规范,在android:configChanges 属性增加 screenSize|screenLayout|orientation|smallestScreenSize,并在Activity的onConfigurationChanged回调中更新宽高刷新各个子布局。

3.4 视频全屏

分屏时请求横屏还是在分屏下显示,无法横屏全屏

建议配置activity 始终填满任务窗口:

<ActivityRule  
    window:alwaysExpand="true">
    <ActivityFilter    
        window:activityName=".FullActivity"/>
</ActivityRule>

3.5 clearTop标记

若配置为true

启动activity窗口分屏,存在相同的primary container,会创建新的secondary container,原来的secondary container中的activity会被finish掉,避免右分屏出现多实例。开发者可以根据需要对单独的SplitPairRule 进行配置clearTop=”true”。

小米开发平台Activity Embedding 适配指南小米开发平台Activity Embedding 适配指南

用户折叠手机时,屏幕 B 在屏幕 A 之上,屏幕 A 又在菜单之上。当用户从屏幕 B 进行返回导航时,系统会显示屏幕 A 而不是Menu。

可以将分屏配置为通过 clearTop 清除之前的辅助容器,并正常启动新的 activity。

<SplitPairRule
    window:clearTop="true">
    <SplitPairFilter
        window:primaryActivityName=".Menu"
        window:secondaryActivityName=".ScreenA"/>
    <SplitPairFilter
        window:primaryActivityName=".Menu"
        window:secondaryActivityName=".ScreenB"/>
</SplitPairRule>

3.6 new Task与Launch Flag

当分屏任务窗口中的 activity 启动新任务中的 activity 时,新任务将与包含分屏的任务分开并显示在全窗口中。

在分屏任务窗口中,Launch flag同样起作用,可以复用activity。

小米开发平台Activity Embedding 适配指南小米开发平台Activity Embedding 适配指南

3.7 多进程规则匹配

问题:同一Task任务下,子进程配置activity成全屏不生效

小米开发平台Activity Embedding 适配指南小米开发平台Activity Embedding 适配指南

采用Jetpack Startup不指定android:process时默认在主进程初始化SplitController,在xml文件夹中的分屏规则不会在子进程生效

<!-- AndroidManifest.xml -->
<provider android:name="androidx.startup.InitializationProvider"
  android:authorities="${applicationId}.androidx-startup"
  android:exported="false"
  tools:node="merge">
  <!-- This entry makes ExampleWindowInitializer discoverable. -->
  <meta-data android:name="**androidx.window.sample.embedding.ExampleWindowInitializer**"
    android:value="androidx.startup" />
</provider>

目前解决方案是需要重写Application在onCreate方法中对需要规则匹配的进程初始化SplitController并且加载静态规则。

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        SplitController.initialize(getApplicationContext(), R.xml.split_config);
        super.onCreate();
    }
}

3.8 响应分屏状态变化

ActivityEmbedding下如何判断activity是否处于分屏以及window mode变化,如何实时响应分屏状态变化。

3.8.1 判断是否在左右分屏

左右分屏下,activity中的configuration的mode是multi-window(与系统分屏下的mode一样,在进行部分业务处理时需要注意)

全屏状态下,activity中的configuration的mode是fullscreen

判断当前activity是否在左右分屏状态,可以通过SplitController.getInstance().isActivityEmbedded(Activity activity)进行区分,返回true表示处于分屏。

3.8.2 如何响应分屏状态变化

为了知道 activity 何时在分屏中,可以向SplitController注册一个监听器来监听分屏状态的变化。然后,相应地调整界面:

小米开发平台Activity Embedding 适配指南小米开发平台Activity Embedding 适配指南
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    splitController
        .addSplitListener(this, mainThreadExecutor, SplitInfoChangeCallback());
}

class SplitInfoChangeCallback extends Consumer<List<SplitInfo>> {
    public void accept(List<SplitInfo> splitInfoList) {
        findViewById<View>(R.id.infoButton).visibility =
            !splitInfoList.isEmpty()) ? View.GONE : View.VISIBLE;
    }
}

可以在任何生命周期状态下进行回调,包括当 activity 停止时。通常应在onStart()中注册监听器,在onStop()中取消注册监听器。

3.9 占位Activity Placeholder

小米开发平台Activity Embedding 适配指南小米开发平台Activity Embedding 适配指南

如需创建带有占位符的分屏,请创建一个占位符并将其与主要 activity 相关联:

<SplitPlaceholderRule  
window:placeholderIntentName=".Placeholder">  
<ActivityFilter    
    window:activityName=".Main"/>
</SplitPlaceholderRule>

注意:开发者不需要自己启动placeholder,会创建多个TaskFragment导致启动异常,在真正显示主页面时建议不启动placeholder,可以动态注册规则,比如在进入主界面前先跳转到登录界面,如果启动了placeholder有可能会导致异常。

编辑:yimen,如若转载,请注明出处:https://www.yimenapp.com/kb-yimen/12658/

部分内容来自网络投稿,如有侵权联系立删

未经允许不得转载:一门应用 » 小米开发平台Activity Embedding 适配指南
分享到

相关推荐

联系我们

微信公众号

yimendabao

关注官方微信,了解最新资讯

客服QQ
4001658508

企业QQ,点击发起咨询