GradleスクリプトによるManifestファイルの管理
11072 ワード
コンパイル時に異なるmanifestを区別する
多くのAndroidプロジェクトでは、debugとreleaseのmanifestファイルを区別してデバッグし、一部のコンポーネント化されたプロジェクトでは、異なるコンポーネントをデバッグするために複数のmanifestファイルもあります.簡単な例を挙げるとappのbuild.gradleファイル:
この場所のif条件は、一般的に変数であってもよいし、方法であってもよい.
次に、ここでの${projectDir}変数は、現在のモジュールが存在するパスに対応します.ここでappのパスであり、エンジニアリング全体のパスではありません.これにより、異なるmanifestファイルをコンパイルすることができます.
自動判定コンパイルタイプ
しかし、このようにコンパイルするたびにそのdebug変数を手動で変更する必要があるのは面倒です.特に、一部の技術チームは、会社のサーバをオンラインでコンパイルし、毎回コードを倉庫に提出する可能性があります.gradleプラグインの特性を用いて判断することができます
コードを変更する必要はありません.releaseパッケージとdebugパッケージを打つと自動的に区別されます.もちろん、新しい条件を追加して、異なるコンパイルtaskに対応することもできます.
manifestファイルの解析と自動生成
この部分は本文の重点です!上記の手順から見ると、manifestファイルを2部用意しているのは明らかで、普段のメンテナンス時にも一緒に修正する必要があります.実際のビジネスではdebugとreleaseのmanifestの内容があまり悪くない可能性があります.一部のコンポーネントノードの属性が異なるだけで、手動で変更するのも面倒です.
gradleスクリプトでmanifestファイルを動的に変更して生成できますか?もちろんいいです.本質的にはXMLファイルを処理します.AndroidManifestは標準的なXMLファイルです.ちょうど、GroovyはXMLを処理するのがとても簡単です.ここでは実際の例で話します.
たとえば、debugテストでは、デスクトップアイコンが正常に表示され、releaseリリースでは非表示にする必要があります.では、2つのmanifestファイルはこうです.
releaseバージョンのmanifest:
そして、通常の開発では、4つのコンポーネントを追加すると、2つのファイルが同時に増加しますが、違いはエントリActivityだけです.私たちが望んでいるのはreleaseバージョンのmanifestが自動的に生成される(生成時にそのdataノードを挿入する)ことであり、普段はdebugバージョンを変更するファイルを開発するだけでよい.
主な考え方は簡単です. GroovyのXML解析ライブラリを介してdebugのmanifestファイルを読み込み、ノードを巡ってエントリActivityを見つけます. dataノードをエントリActivityの下に挿入する. は、releaseバージョンのファイルに新しい内容を書き込む.
まず直接見てください.gradleスクリプトソース:
重要な論理は
次に
いくつかの小さな問題
Windows開発者であれば、最後にファイルを書くときは、改行や符号化の問題に注意する必要があります.
1、最後のwriteメソッド、パラメータを加える:
あるいは直接グローバル構成を変更し、工事全体のgradleを変更する.propertiesファイルは、gradleのJVMパラメータの後に次のように追加されます.
2、改行文字の問題、JVMパラメータが修正できない場合、手動で処理するか、最後にwriteするかしかできない場合:
ここでXmlUtilツールクラスのserializeメソッドの戻りタイプは実際にStringなので、このように直接replaceすることができます.
多くのAndroidプロジェクトでは、debugとreleaseのmanifestファイルを区別してデバッグし、一部のコンポーネント化されたプロジェクトでは、異なるコンポーネントをデバッグするために複数のmanifestファイルもあります.簡単な例を挙げるとappのbuild.gradleファイル:
android {
defaultConfig {
applicationId "com.xxx.xxx"
}
sourceSets {
main {
if( debug ) {
manifest.srcFile "${projectDir}/src/main/debug/AndroidManifest.xml"
} else {
manifest.srcFile "${projectDir}/src/main/release/AndroidManifest.xml"
}
}
}
}
この場所のif条件は、一般的に変数であってもよいし、方法であってもよい.
//
def isDebug = true
//
def isDebug() {
//
return true
}
// Groovy ,Android Gradle Groovy ( JVM , ) 。
android { ... }
次に、ここでの${projectDir}変数は、現在のモジュールが存在するパスに対応します.ここでappのパスであり、エンジニアリング全体のパスではありません.これにより、異なるmanifestファイルをコンパイルすることができます.
自動判定コンパイルタイプ
しかし、このようにコンパイルするたびにそのdebug変数を手動で変更する必要があるのは面倒です.特に、一部の技術チームは、会社のサーバをオンラインでコンパイルし、毎回コードを倉庫に提出する可能性があります.gradleプラグインの特性を用いて判断することができます
// app ,assembleDebug gradle debug task
if(gradle.startParameter.taskNames.contains(":app:assembleDebug")) {
manifest.srcFile "${projectDir}/src/main/debug/AndroidManifest.xml"
} else {
manifest.srcFile "${projectDir}/src/main/release/AndroidManifest.xml"
}
コードを変更する必要はありません.releaseパッケージとdebugパッケージを打つと自動的に区別されます.もちろん、新しい条件を追加して、異なるコンパイルtaskに対応することもできます.
manifestファイルの解析と自動生成
この部分は本文の重点です!上記の手順から見ると、manifestファイルを2部用意しているのは明らかで、普段のメンテナンス時にも一緒に修正する必要があります.実際のビジネスではdebugとreleaseのmanifestの内容があまり悪くない可能性があります.一部のコンポーネントノードの属性が異なるだけで、手動で変更するのも面倒です.
gradleスクリプトでmanifestファイルを動的に変更して生成できますか?もちろんいいです.本質的にはXMLファイルを処理します.AndroidManifestは標準的なXMLファイルです.ちょうど、GroovyはXMLを処理するのがとても簡単です.ここでは実際の例で話します.
たとえば、debugテストでは、デスクトップアイコンが正常に表示され、releaseリリースでは非表示にする必要があります.では、2つのmanifestファイルはこうです.
<manifest ...>
<application ...>
<activity
...
android:name=".TestActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
intent-filter>
activity>
...
releaseバージョンのmanifest:
<manifest ...>
<application ...>
<activity
...
android:name=".TestActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<data
android:host="localhost"
android:scheme="${applicationId}" />
intent-filter>
activity>
...
そして、通常の開発では、4つのコンポーネントを追加すると、2つのファイルが同時に増加しますが、違いはエントリActivityだけです.私たちが望んでいるのはreleaseバージョンのmanifestが自動的に生成される(生成時にそのdataノードを挿入する)ことであり、普段はdebugバージョンを変更するファイルを開発するだけでよい.
主な考え方は簡単です.
まず直接見てください.gradleスクリプトソース:
import groovy.xml.XmlUtil
def getManifestPath(buildType) {
return "${projectDir}/src/main/$buildType/AndroidManifest.xml"
}
def handleManifestXml(manifest) {
if (gradle.startParameter.taskNames.contains(":app:assembleDebug")) {
// debug build
def debugPath = getManifestPath('debug')
manifest.srcFile debugPath
println("Manifest path: $debugPath")
} else {
// release build
def releasePath = getManifestPath('release')
println("Manifest path: $releasePath")
manifest.srcFile releasePath
def debugPath = getManifestPath('debug')
def debugFile = new File(debugPath)
def releaseFile = new File(releasePath)
def debugXml = new XmlParser(false, false).parse(debugFile)
// debug manifest, release
debugXml.application[0].each { comp ->
if (comp.name() == 'activity') {
comp.each { filter ->
// Activity
if (filter.toString().contains('android.intent.category.LAUNCHER')) {
// data , icon
filter.appendNode('data', ['android:host': 'localhost', 'android:scheme': '${applicationId}'])
return true // break each
}
}
}
}
releaseFile.write(XmlUtil.serialize(debugXml))
}
}
android {
defaultConfig {
applicationId "com.xxx.xxx"
}
sourceSets {
main {
// manifest
// : debug manifest , release
handleManifestXml(manifest)
}
}
...
重要な論理は
def debugXml = new XmlParser(false, false).parse(debugFile)
から始まり、ここのXmlParser構造方法はパラメータを送信しなくてもよい.ここでfalseは主にmanifestルートノードにxmlnsを自動的に追加させるために送信され、最終的にファイルの内容が簡潔になる.次に
debugXml.application[0].each { comp -> ... }
ループブロックで、Groovyの構文は不思議で、ここではノード名で配列を直接取得することができます.例えばアプリケーション、0を取るのはもちろん最初です.一般的に私たちのmanifestにはアプリケーションノードがあるので、空のポインタ異常は発生しません.eachは配列の関数で、配列の各ノードを遍歴し、compパラメータは私がカスタマイズした名前です.アプリケーションのサブノードを手に入れることができて、後ですべていくつかの論理処理で、言うまでもありません.いくつかの小さな問題
Windows開発者であれば、最後にファイルを書くときは、改行や符号化の問題に注意する必要があります.
1、最後のwriteメソッド、パラメータを加える:
releaseFile.write(xmlStr, "UTF-8")
あるいは直接グローバル構成を変更し、工事全体のgradleを変更する.propertiesファイルは、gradleのJVMパラメータの後に次のように追加されます.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
2、改行文字の問題、JVMパラメータが修正できない場合、手動で処理するか、最後にwriteするかしかできない場合:
releaseFile.write(XmlUtil.serialize(debugXml).replaceAll('\r
', '
'))
ここでXmlUtilツールクラスのserializeメソッドの戻りタイプは実際にStringなので、このように直接replaceすることができます.