学习powershell的初衷是因为在编写flutter工程模版脚本的过程中遇到一个极不起眼却很棘手的问题:batch脚本无法满足复杂的xml文件修改需求。这是由于xml文件中大量存在<
和>
,这与batch的重定向符是相同的,导致在echo每行xml内容时出现各种莫名其妙的问题。第一时间想到的是flutter SDK是如何处理AndroidManifest.xml的呢?遂开始翻阅flutter SDK中的bat文件(在FLUTTER_HOME的bin文件夹下),发现SDK中涉及到复杂的操作都交给了powershell,于是整理powershell的基本语法有了PowerShell脚本:快速入门一文。言归正传,来看看如何使用powershell实现xml文件的修改。
需求
我们来看看flutter在生成插件工程时example默认生成的清单文件:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.flutter_example">
<application
android:name="io.flutter.app.FlutterApplication"
android:label="flutter_example"
android:icon="@mipmap/ic_launcher">
<!-- 无关部分省略. -->
</application>
</manifest>
根据编译失败的提示信息,主要是application的name、label属性与引入的安卓基础库冲突导致,解决办法很简单,修改成如下的样子:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.flutter_example">
<application
tools:replace="android:label,name"
android:usesCleartextTraffic="true"
android:name="io.flutter.app.FlutterApplication"
android:label="flutter_example"
android:icon="@mipmap/ic_launcher">
<!-- 无关部分省略. -->
</application>
</manifest>
主要有3处修改:
- manifest 增加了xmlns:tools=“http://schemas.android.com/tools”
- application增加了tools:replace=“android:label,name”
- application增加了android:usesCleartextTraffic=“true”
思路自然是为doc的manifest 和application新增对应的属性即可,具体操作可以参照PowerShell脚本:快速入门中xml章节。
然而有个问题,用setAttribute(string name, string value)方法设置application属性时,调用:$application.setAttribute('tools:replace', 'android:label,name')
,实际生成的却是:replace="android:label,name"
,命名空间没了!!!
解决思路:查看node和attribute的数据类型以及相应的类方法,看看是否有重载方法可以满足需求。分别对node和attribute对象执行get-member查看所有类方法:$var | get-memer
,然后根据方法名进行测试,最终找到node具有setAttribute方法的重载setAttribute(string name, string nsUri, string value)可以解决命名空间丢失的问题,最终的解决方案如下:
实现
param([string]$examplePath=$(throw "Where is example code path?"))
# 找到要修改清单文件的绝对路径
$srcPath=$examplePath+"\android\app\src\main\AndroidManifest.xml"
# 创建doc对象
[XML]$manifest = gc $srcPath
$rootNode=$manifest.selectNodes('/manifest[1]')
$toolsUri="http://schemas.android.com/tools"
$androidUri="http://schemas.android.com/apk/res/android"
# 修改manifest节点属性
$rootNode.setAttribute("xmlns:tools","http://schemas.android.com/tools")
$app=$manifest.selectNodes('/manifest/application[1]')
# 修改application节点属性
$app.setAttribute('replace',$toolsUri,'android:label,name') | Out-Null
$app.setAttribute('usesCleartextTraffic',$androidUri,'true') | Out-Null
# 将doc修改保存到源文件
$manifest.Save($srcPath) | Out-Null