API环境切换需求
需求背景
鉴于app在打包debug ,release, dev 等环境的时候,请求后天api接口的服务器地址不一样.导致测试可能频繁的问你要不同环境的测试apk包.
当工程大到一定程度的时候,gradle打包特别的慢.即使你自己有优化过,而且测试嫌麻烦,开发也觉得麻烦.
实现思路
api地址变化的应该就基地址,全部变化也有办法处理.这里把基地址用一个 public static 的 String Url 变量去装载.
1:默认 Url 地址使用release的地址.
2:release版本的apk 按照需求,启动app调转到splash界面.debug版本的apk 跳转到api选择界面,当选择好api环境后,在调转到原splash界面.
3:选择api环境的时候,去修改 这个被public static 修饰的Url
实现策略
1:修改被public static 修饰的String 不是问题.
2:根据不同apk版本启动不同的界面.这个是一个问题,之前没处理过类似的需求.好在google 有提供一种解决思路 饺子 manifest merge (合并多个清单文件),就是根据这个合并算法去解决这个问题.
实现细节
第一步
创建debug文件夹,新建的项目一般会有3个文件夹,一个是默认类型,一个test 类型,一个Android test类型,这里我们在创建一个debug类型的.
xml文件合并可以合并java 文件,和 资源文件.
我们这里定要创建manifest文件,这是算法配置的核心,配置就是在这里设置的,其次还有资源文件.
注意创建的时候文件格式应该和main类型的保持一致,可以将as切换到android模式下检查.
我们这里添加了一个EnvChangeActivity 和对应的布局文件.
第二步:合并要合并的文件
这里我们想修改启动的界面为EnvChangeActivity.所以我们要替换点原main类型下的manifest文件中的配置.
如上设置就会把原Mainactivity中的配置全部替换成当前manifest文件中的配置.后面我们在解释这些配置.这里将EnvChangeActivity设置成了启动界面.所以完成了修改启动界面的功能.
第三步
创建一个java配置文件
可以不创在main类型下面.
在EnvChangeActivity中修改地址就好了.修改完之后在跳转到MainActivity.就原逻辑保持一致了
到这里需求的就已经说明完了.
合并
接下来就说明合并的算法,在我们使用gradle编译打包的时候,合并工具会自动帮我们合并.
合并工具根据每个清单文件的优先级将所有清单文件按顺序合并到一个文件中。 例如,如果您有 3 个清单文件,则会先将优先级最低的清单合并到优先级第 2 高的清单中,然后再将合并后的清单合并到优先级最高的清单中
1清单文件构建变体如果您的变体有多个源集,则其清单优先级如下:
构建变体清单(如 src/demoDebug/)
构建类型清单(如 src/debug/)
产品定制清单(如 src/demo/)如果您使用的是定制维度,清单优先级将与每个维度在 flavorDimensions
属性中的列示顺序(按优先级由高到低的顺序排列)对应。
2应用模块的主清单文件
3所包括库中的清单文件如果您有多个库,则其清单优先级与依赖顺序(库出现在 Gradle dependencies
块中的顺序)匹配。
合并冲突启发式算法
合并工具可以在逻辑上将一个清单中的每个 XML 元素与另一个清单中的对应元素相匹配。
如果优先级较低的清单中的元素与优先级较高的清单中的任何元素均不匹配,则该元素将被添加至合并清单。 但是,如果有匹配元素,则合并工具会尝试将其中的所有属性合并到相同元素中。如果工具发现两个清单包含相同属性,但值不相同,则会出现合并冲突。
但是,在某些情况下,合并工具会采取其他行为方式以避免合并冲突:
<manifest>
元素中的属性绝不合并—仅使用优先级最高的清单中的属性。
android:required 属性 <uses-feature>and <uses-library>
元素使用 OR 合并,因此如果出现冲突,系统将应用 "true"
并始终包括某个清单所需的功能或库。<uses-sdk>元素始终使用优先级较高的清单中的值,但以下情况除外:如果低优先级清单的 minSdkVersion 值较高,除非您应用 overrideLibrary合并规则。
如果低优先级清单的 targetSdkVersion 值较低,合并工具将使用高优先级清单中的值,但也会添加任何必要的系统权限,以确保所导入的库继续正常工作(适用于较高的 Android 版本具有更多权限限制的情况)。
绝不会在清单之间匹配 <intent-filter>
元素。 每个元素都被视为唯一元素,并添加至合并清单中的常用父元素。
合并规则标记
合并规则标记是一个 XML 属性,可用于表达您对关于如何解决合并冲突或删除不需要的元素和属性的首选项。 您可以对整个元素或只对元素中的特定属性应用标记。
合并两个清单文件时,合并工具会在高优先级清单文件中寻找这些标记。
所有标记均属于 Android tools 命名空间,因此您必须先在 <manifest> 元素中声明此命名空间,如下文所示:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp"
xmlns:tools="http://schemas.android.com/tools">
节点标记
要向整个 XML 元素(给定清单元素中的所有元素及其所有子标记)应用合并规则,请使用以下属性:
tools:node="merge"
如果使用合并冲突启发式算法时没有冲突,则合并此标记中的所有属性以及所有嵌套元素。这是元素的默认行为。
低优先级清单
<activity android:name=”com.example.ActivityOne”
android:windowSoftInputMode=”stateUnchanged”>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
高优先级清单
activity android:name=”com.example.ActivityOne”
android:screenOrientation=”portrait”
tools:node="merge”>
</activity>
合并结果
<activity android:name=”com.example.ActivityOne”
android:screenOrientation=”portrait”
android:windowSoftInputMode=”stateUnchanged”>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
tools:node="remove"
低优先级清单
<activity-alias android:name=”com.example.alias”>
<meta-data android:name=”cow”
android:value=”@string/moo”/>
<meta-data android:name=”duck”
android:value=”@string/quack”/>
</activity-alias>
高优先级清单
<activity-alias android:name=”com.example.alias”>
<meta-data tools:node=”removeAll”/>
</activity-alias>```
合并结果
<activity-alias android:name=”com.example.alias”>
</activity-alias>
tools:node="replace"
完全替换低优先级元素。 也就是说,如果低优先级清单中有匹配元素,请将其忽略并完全按照其在此清单中显示样子来使用该元素。
低优先级清单
<activity-alias android:name=”com.example.alias”>
<meta-data android:name=”cow”
android:value=”@string/moo”/>
<meta-data android:name=”duck”
android:value=”@string/quack”/>
</activity-alias>```
高优先级清单
<activity-alias android:name=”com.example.alias”
tools:node=”replace”>
<meta-data android:name=”fox”
android:value=”@string/dingeringeding”/>
</activity-alias>
合并结果
<activity-alias android:name=”com.example.alias”>
<meta-data android:name=”fox”
android:value=”@string/dingeringeding”/>
</activity-alias>