问题
假如项目突然有一个支持pad的需求,需要将所有的页面都支持横屏,该怎么做?
常见方案:
- 将manifest的中活动的
screenOrientation
属性都固定为unspecified
,问题就是手动修改十分麻烦,且项目本身是增量编译的情况下,必须使用耗时的全量编译才行; - 使用BaseActivity或者ActivityLifecycleCallbacks中动态去设置(kotlin):
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
问题在于这种方式在Android10上有问题,横屏跳转到下一个活动,手机会先竖屏展示,然后再自动切成横屏,也就是“跳一下”。
问题解决
目标一:自动化修改manifest文件,使其支持增量编译
思路:在Gradle构建APK的过程中,在总的manifest文件生成(每个Module的manifest文件自动合并后)之后,将所有的screenOrientation
都改动成unspecified
,这样不管在哪种编译模式下都能将所有页面都改动到:
//在app下的build.gradle文件末尾中添加
//此处是kts脚本,换成groovy脚本照着抄就行,大同小异
//将所有的竖屏修改为unspecified,为了测试,临时把代码放在这里
//项目构建之后
project.afterEvaluate {
//获取输入,包含了资源输入和manifest输入(输入-transform-输出)
//其实也可以自己对 process[XXX]Manifest 相关的几个task直接操作
android.applicationVariants.forEach { variant->
variant.outputs.forEach { output ->
val manifestTask = output.processManifestProvider.orNull
if (manifestTask != null) {
doLastReplaceManifest(manifestTask)
} else {
val taskName = output.processManifestProvider.name
project.tasks.whenTaskAdded(object : Action<Task> {
override fun execute(t: Task) {
if (t.name == taskName) {
doLastReplaceManifest(output.processManifestProvider.get())
}
}
})
}
}
}
}
fun doLastReplaceManifest(task: com.android.build.gradle.tasks.ManifestProcessorTask) {
task.doLast {
val startTime = System.currentTimeMillis()
val manifestPath = "${task.manifestOutputDirectory.get().asFile.absolutePath}/AndroidManifest.xml"
val file = file(manifestPath)
if (!file.exists()) {
println("not find manifest file, path=${file.absolutePath}")
return@doLast
}
val str = file.readText()
file.setWritable(true)
file.writeText(str.replace(
"screenOrientation=\"portrait\"",
"screenOrientation=\"unspecified\""
))
println("replace portrait to unspecified, spent ${System.currentTimeMillis() - startTime}ms")
}
}
其实方案一有一个问题就是,当需要动态改变屏幕方向的时候就还是会“跳一下”。
例如在上面的基础上再加上下面的动态代码(固定为横屏)
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
目标二:解决安卓10动态修改屏幕方向“跳一下”问题
在探索时发现,对于一个活动,manifest中它的screenOrientation
只是locked
的时候,动态去修改屏幕方向,它就不会再“跳一下”。
举个简单例子:
//manifest.xml
<activity android:name=".MainActivity2"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
android:screenOrientation="locked">
//Activity.kt
override fun onCreate(savedInstanceState: Bundle?) {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
super.onCreate(savedInstanceState)
}
至于自动化的过程,请参照方案一。
网友评论