はじめに
今回と次回の2回にかけて、イマイチよくわかってないAndroid Studioのプロジェクト管理ファイルについて解説します。途中で飽きちゃう人のために、最低限共有する必要のある(バージョン管理する必要のある)管理ファイルを紹介します。
ここでの対象は.idea
ディレクトリだけなので、説明のしやすさも兼ねて <PROJECT_HOME>/.idea/.gitignore
を作成し「.idea
ディレクトリに対するホワイトリスト」を提示していきます。
図1 新しく<PROJECT_HOME>/.idea/.gitignoreを作成する
リスト1 最低限必要な<PROJECT_HOME>/.idea/.gitignoreの例
*.xml
!/gradle.xml
リスト2 最低限必要な<PROJECT_HOME>/.idea/.gitignoreの例.gitignoreの内容
/.gradle/
/local.properties
.DS_Store
*.iml
前回 紹介した.gitignore
はbuild.gradle
以外を除外するため、Android Studioにとっては「Gradleのプロジェクト」と認識します。「 Android Studioのプロジェクト」として認識させるには「<PROJECE_HOME>
に.idea
ディレクトリがあること 」で、その中身を必要最低限まで削るとgradle.xml
だけが残ります。
.idea/gradle.xml
だけあればAndroid Studioは、そのディレクトリを自身のプロジェクトとして認識します。あとは、必要に応じて他に共有したい設定を追記していくことになります。どんなときに/どの設定ファイルを共有したら良いかが中編・後編の内容になります。
[注意].idea/gradle.xmlを共有するときの注意事項
Android Studioのバージョンやプラットフォームによってバラツキがあるのですが、v0.3.6~v0.3.7のWindows版では gradle.xml
にその環境の絶対パスが含まれます(詳しくは本編で解説します) 。これが共有の妨げになるので、gradle.xml
をコミットする前に、その中身を確認してください。
リスト3 絶対パスが含まれているgradle.xmlの例
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="C:\Users\masanobuimai\AndroidStudioProjects\MyApplication" />
</GradleProjectSettings>
"externalProjectPath "のvalue
に絶対パスが設定されているようであれば、これを直接編集してリスト4 のように修正してください。設定している内容は意味的に変わりありません。IntelliJ IDEA13などは絶対パスではなく$PROJECT_DIR$
と登録されるので、単純にAndroid Studio側のバグなのだと思います。
リスト4 絶対パスを除いたgradle.xmlの例
<option name="externalProjectPath" value="$PROJECT_DIR$"/>
Android Studioの管理ファイルについて
Android Studioの管理ファイルは大きく分けて次の二種類があります。
モジュール定義ファイル(*.iml
)
Android StudioやIntelliJでは、プロジェクトは「場」であって、その中にモジュールという「実体」があります。Eclipseにたとえると、プロジェクトが(Eclipseの)ワークスペースで、モジュールが(Eclipseの)プロジェクトです。
モジュール定義ファイル(*.iml
)はそのモジュールごとの定義情報を保存しています。もう少し具体的に言うと「Project Structure」の設定内容がここに保存されます。ちなみに、このファイルの中身はXMLです。
.idea
ディレクトリ配下の設定ファイル
<PROJECT_HOME>
直下にある.idea
ディレクトリです。ここには主にプロジェクト固有の設定情報が格納されます。もっと具体的に言うと「Preferences」の「Proejct Settings」部分のほとんど と、( 本連載ではまだ説明していませんが)「 Run/Debug Configuration」の一部 が保存されます。
このディレクトリに保存される設定ファイルもすべてXMLファイルです。厳密なルールはありませんが「Preferences」の設定項目ごとに設定ファイルが独立しています。
Android Studioは、この.idea
ディレクトリを含むディレクトリを「プロジェクト」と認識します。ディレクトリ名が.idea
なのは、Android StudioのベースとなったのがIntelliJ IDEA だからです。実を言えば、IntelliJベースの他のIDEもすべてこの形式なので、複数のJetBrains系IDEを併用している場合はちょっとした混乱の元になります。
これらの設定ファイルも基本的にはバージョン管理下に置き共有するのが望ましいと言われています。一応、公式な見解があり、それに従うと次のようになります。
.idea/workspace.xml
と.idea/tasks.xml
は共有してはいけない。
.idea/dictionary/
も共有しないほうがいい。
これ、間違ってはいないのですが、正解でもありません。共有しないほうが良いファイルはもう少しあり、一部の設定ファイルは条件に応じて 共有するかどうかを決めた方がよいものがあります。そして何より情報が古いです。
また、github / gitignore にあるJetBrains.gitignore もだいぶ極端な設定になっています。
モジュール定義ファイル(*.iml)
モジュール定義ファイルには、いつの頃からか隠してしまった「Project Structure / Modules」に関する情報が保存してあります。v0.3.6から「Project Structure」が復活しましたが、build.gradle
の編集用に特化してしまって、モジュール定義とかけ離れています。
図2 v0.3.6以降の「Project Structure」設定画面
モジュール定義ファイル本来の設定情報については、第5回 を参照してください。
最近のAndroid Studioの「Project Structure」からはIntelliJっぽさが無くなってきていますが、ユーザインタフェースを隠しているだけで設定ファイルの内容そのものは依然健在です。ただ、Android Studioにとって「Project Structure」の元ネタ(原本)はあくまでbuild.gradle
であって、モジュール定義ファイル(*.iml
)はその写像でしかないのです。
別の見方をすると、次のような考え方が成り立ちます。
モジュール定義ファイル(*.iml
)はbuild.gradle
から生成可能な二次情報なので管理する必要がない。
実際、故意にモジュール定義ファイルを削除してから、そのプロジェクトをAndroid Studioで開き直すと消したはずのモジュール定義ファイルが再構築されます。
ちなみに「このプロジェクトを構成しているモジュール群」は.idea/modules.xml
に記録されるので、*.iml
ファイルを意図的に削除するときは、このファイルもあわせて削除してください。
結論
モジュール定義ファイルの情報はbuild.gradle
から再生成することができるので、あえてバージョン管理対象にする必要はありません。チェックアウトしたディレクトリ名に左右されること無くプロジェクトを開く事ができるため余計なトラブルに遭遇しないで済みます。
Android StudioのプロジェクトはGradleベースであるため、この理屈が成り立つのであって、そうではないプロジェクトの場合はモジュール定義ファイル(*.iml
)がプロジェクト構造を把握している唯一の設定ファイルになります。何が言いたいのかわかりますよね。
モジュール定義ファイルをバージョン管理対象にすることはやぶさかではありませんが、この設定を共有することの制約を理解したうえで実施してください。
モジュール定義ファイルに登録されている情報のうち、共有する際に気を遣うのは「モジュールが使用するAndroid SDKの名称」です(リスト5 ) 。
リスト5 モジュール定義ファイルのコンパイラ設定の例
<orderEntry type="jdk" jdkName="Android API 19 Platform" jdkType="Android SDK" />
プロジェクトが使用するコンパイラのバージョンは、build.gradle
のcompileSdkVersion
に指定しますが、その具体名は「各自が使っているAndroid Studioの/該当するバージョンの/Android SDKの登録名」になります。
きっとチームの誰かが最初にAndroid Studioでプロジェクトを作ると思いますが、モジュール定義ファイルの該当項目には、その人が使ったAndroid StudioのAndroid SDKの登録名が設定されるというわけです。この「Android SDKの登録名」は環境によって微妙に異なる可能性があると前回 紹介しましたが、その話がここにつながります。
よって、モジュール定義ファイルを共有する場合は、各自が使うAndroid StudioのAndroid SDKの登録名を揃えておくこと が条件になります。
プロジェクト管理ファイル(.ideaの中身)
先ほど説明したとおり、.idea
ディレクトリには「Preferences」の「Project Settings」の内容と、ごく僅かですが「Project Structure」や「Run/Debug Configuration」の内容も保存されています。
「Preferences」関連は次回紹介しますので、今回はそれ以外の設定ファイルについて説明しておきます。
プロジェクト設定、モジュールの関連設定ファイル(Project Structure)
.idea/misc.xml
, .idea/modules.xml
簡単なほうから説明します。.idea/modules.xml
は名前から想像がつくように「モジュールの関連」を定義した設定ファイルです。プロジェクトに登録されているモジュールがどこにあるかが登録されています。要するに「Project Structure / Modules」の内容そのものです。
リスト6 .idea/modules.xmlの例
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/MyApplication.iml" filepath="$PROJECT_DIR$/MyApplication.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
</modules>
</component>
</project>
Android Studioの元になったIntelliJでは、モジュールはどこに作っても構わなかったのですが、Android StudioはGradleとの都合もあってプロジェクト(<PROJECT_HOME>
)の中にしかモジュールを作ることができません。
もう一方の「プロジェクト設定」ですが、これは「Project Structure / General Settings for Project」の事で、この内容は.idea/misc.xml
に保存されます。
図3 「 Project Structure / General Settings for Project」設定画面
IntelliJでは普通に見かけるこの画面(「 Project Structure / Project」 )ですが、Android Studioでこの画面に辿り着くのは至難の業です。というかAndroid Studioとしては見せたくない設定画面で、たまたまうっかり出てしまった、が正しい理解なのでしょう。
結論
.idea/modules.xml
モジュールの定義ファイル(*.iml
)と同じく、このファイルもbuild.gradle
から復元できます。よって、この設定ファイルもバージョン管理対象にする必要はありません。要するに*.iml
の管理方法に合わせます。
.idea/misc.xml
「Project Structureの設定」という点では共有は不要です。ただし「その他(misc) 」の意味合いでは他の情報も保持しているため、共有すべきかどうかは次回まで保留にします。
ライブラリの定義(Project Structure)
.idea/libraries/<ライブラリ名>.xml
プロジェクトに登録しているライブラリの情報がライブラリごとに保存されています。ファイル名は <ライブラリ名>.xml
です。ここの内容は「Project Structure / Modules」設定画面の「Dependencies」タブの内容に基づきます。要するに build.gradle
の dependencies
から派生した情報です。
build.gradle
や「Project Structre」に定義するライブラリは大きく次の2種類に大別できます。
プロジェクト内にライブラリの実体があるもの
<PROJECT_HOME>
内のどこかにライブラリの実体(*.jar
)があり、build.gradle
のdependencies
に file
として参照してあるものです(大抵は<PROJECT_HOME>/<MODULE_HOME>/libs
に置きます) 。
リスト7 プロジェクト内のライブラリを参照するbuild.gradleの例
dependencies {
compile files('libs/android-support-v4.jar')
}
※初期の頃のAndroid Studioが生成する build.gradle
がこのパターンでした。
プロジェクト内にライブラリの実体が無いもの
Android SDKやMavenリポジトリを参照するライブラリです。実体(*.jar
)は <PROJECT_HOME>
の外にあります。build.gradle
のdependencies
にリスト8 のように参照してあるものです。
リスト8 外部のライブラリを参照するbuild.gradleの例
dependencies {
compile 'com.android.support:appcompat-v7:+'
}
※最近のAndroid Studioが生成するbuild.gradle
はこのパターンです。
ここでクセ者なのが後者の「プロジェクト内にライブラリの実体が無いもの」です。ライブラリ定義ファイルの内容は、参照しているライブラリのパス情報そのもの が記録されます。プロジェクト内にその実体がある場合は、<PROJECT_HOME>
からの相対パスとして記録してありますが、プロジェクト外の場合、その絶対パス が記録されます。
リスト9 .idea/libraries/support_v4_18_0_0.xmlの例
<component name="libraryTable">
<library name="support-v4-18.0.0">
<CLASSES>
<root url="jar://$USER_HOME$/AndroidSDK/extras/android/m2repository/com/android/support/support-v4/18.0.0/support-v4-18.0.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
Android SDKやGradleのホームディレクトリは環境によって異なるため、このファイルを共有するのは非常に困ることになります。
結論
では、どうしたらよいか?という話になりますが、答えは簡単で共有しません 。
幸いなことにAndroid StudioのプロジェクトはGradleベースであるため、参照ライブラリの情報は build.gradle
に記述してあります。.idea/libraries
が存在しない場合、builg.gradle
を元にライブラリ定義を再構築するので、このディレクトリが無くても何の問題もないのでした。
実行構成の設定
.idea/runConfigurations/<構成名>.xml
この連載ではまだきちんと説明していない「実行構成(Run/Debug Configuration) 」の内容が保存されます。名前から内容は想像できると思いますが、プロジェクトを実行してみるときの構成(エミュレータなのかテストランナーなのか、など)を指定するものです。
実行構成は複数の設定を持つ事ができ、さらにその設定ごとに共有(Share)するかどうかを指定できます。
図4 「 Run/Debug Configurations」設定画面(クリックすると動きがわかります)
「Run/Debug Configurations」ダイアログで「Share」をONした場合のみ、このディレクトリに <構成名>.xml
として保存されます。
結論
わざわざ共有指定をするくらいなので、当然その設定ファイルは共有対象にすべきでしょう。それ以前に実行構成を共有したい用途がどれほどあるか?という疑問というか興味が残ります。
なお、共有設定をしていない実行構成や「現在選択中の実行構成の名前」は .idea/workspace.xml
に記録されます。
.idea/.name とはナニモノ?
.idea
ディレクトリにひっそり潜んでいる .name
ファイルですが、これには「そのプロジェクトのタイトル」が記録されています。
リスト8 .idea/.nameファイルの例
My Application
このファイルがどこに機能しているかというと、タイトルバーやウェルカム画面に表示されるプロジェクト名で使われています。
図5 .idea/.nameの値の利用箇所の例
共有して邪魔になることは無いので共有しておきます。冒頭に提示した .idea/.gitignore
は *.xml
を除外しているので、この .name
ファイルは共有対象に含まれます。ちなみに、このファイルが無いとプロジェクトのディレクトリ名(<PROJECT_HOME>
)が採用されます。
場合によっては、.idea/.name
が無いほうが都合が良いときもあると思いますので、このファイルを共有すべきかどうかはプロジェクトの特性に応じて決定してください。
中編のまとめ
「Project Structre」まわりは build.gradle
から再生できるのと、ヘンに共有すると環境の調整が面倒なので共有対象にはしません。それ以外では、実行構成(Run/Debug Configurations)は「共有する(Shared) 」と明示するので、共有対象にしないわけにはいきませんよね。
というわけで、冒頭に示した.idea/.gitignore
はリスト10 のようになります。
リスト10 中編のまとめによる<PROJECT_HOME>/.idea/.gitignore の例
*.xml
!/gradle.xml
!/runConfigurations/*.xml
残りの設定ファイルについては次回に続きます。
番外編:チェンジリスト(Changelist)ってなに?
突然ですが、第23回 や第26回 でもったいぶった言い回しをしていた「チェンジリスト(Changelist) 」について解説します。
Android Studioでバージョン管理操作を行う場合、エディタから/「 Projectツールウィンドウ」から/「 Changesツールウィンドウ」からなどさまざまなやり方があることを紹介しました。その中でも筆者がオススメするのは、だんぜん「Changesツールウィンドウ」から操作する方法です。
昔話になりますが、Android Studioの元になったIntelliJではバージョン管理の操作は「Changesツールウィンドウ」でしかできませんでした。その後のバージョンアップに伴い、他のIDEみたく「Projectツールウィンドウ」でもできるようになったわけなのです。そんな経緯もあってか、バージョン管理に関する諸々の操作は「Changesツールウィンドウ」のほうが便利に使えるようにできているのです。
その端的な機能が「チェンジリスト」です。「 Changesツールウィンドウ / Localタブ」にある「Default」は、そのチェンジリストのひとつの例です。
図6 「 Changesツールウィンドウ / Localタブ」にある「Default」チェンジリスト
このチェンジリスト、何が便利かと言うと、チェンジリストごとに「変更のカタマリ(コミットする単位) 」を複数管理することができます。たとえば、とある変更作業を行っていたとき、偶然にも関係のない修正箇所を見つけた場合を考えてみましょう。
そんなときに取れる対応はだいたい次の2通りになると思います。
まずは今の作業を終わらせて(コミットして)から、そっちを修正する。
とりあえず修正して、コミットするとき複数回に分けて修正する。
いずれにしろ、作業者の負担(メモっておかないといけない、うっかりミスの元になる、など)が少なくありません。そんなときにチェンジリストを使うと便利です。
あるファイル群(foo.txt
, bar.txt
)を修正中に、どうしても他のファイル群(boo.txt
, hoge.txt
)を修正してしまった場合、「 Changesツールウィンドウ / Localタブ」のDefaultチェンジリストから一方のファイル群を選び、コンテキストメニューから「Move to Another Changelist」を実行し、新しいチェンジリストに移動させます。
図7 新しいチェンジリストの作成(クリックすると動きがわかります)
これでboo.txt
, hoge.txt
は別のチェンジリストに属したことになります。
チェンジリストは必ずどれかひとつが Active状態 になります(Active、非Activeの切り替えはツールバーやコンテキストメニューでできます) 。ファイルを編集したり、その変更結果をコミットする場合、Activeなチェンジリストがその対象となります。
図8 チェンジリストの切り替え(クリックすると動きがわかります)
※Activeなチェンジリストが一番上に表示されます(とても見づらいですが、太字 になっています) 。
チェンジリストを活用することで、ローカルで編集した内容を一律にコミットするのではなく目的別に分けてコミットすることができます。ここまで聞いてピンとくる人にとってはとても便利な機能です。あまり良い例ではありませんが、一番よく使う用途は、プログラムの修正と、その間にPreferencesやProject Structreなどを弄って変更が発生してしまったAndroid Studioの設定ファイルを別に管理する事です。
図9 チェンジリストを使って設定ファイルの変更を別に管理する
なお、Activeではないチェンジリストに属するファイルを編集してしまった場合は「そのファイルを今のチェンジリストに移すか?(Move changes) 」 「 Activeなチェンジリストを切り替えるか?(Switch changelist) 」 「 なにもしないか?(Ignore) 」と聞いてきます。
図10 Activeでないチェンジリストのファイルを修正した場合
ただし、さすがに同じファイルを複数のチェンジリストで共有することはできません。また、チェンジリストの概念そのものはAndroid Studio独自のものです。そのため、使っているバージョン管理システムのコマンドや他のクライアントでコミット操作を行うと、チェンジリストに関係なく全ての変更がコミットされます。
チェンジリストの管理方法もさまざまです。前述したとおり、既存のチェンジリストの一部から新しいチェンジリストを作成するする方法もあれば、ツールバーの「+」アイコン("New Changelist ")からまっさらなチェンジリストを作ることもできます。また、ドラッグ&ドロップでチェンジリスト間のファイルを移動できます。
図11 チェンジリスト間のファイルの移動(クリックすると動きがわかります)
チェンジリストはコミット単位そのものであるため、この概念を利用してバグ管理システム(BTS)や課題管理システム(ITS)と連携することが可能です。この件については、次回の番外編で説明します。
さらに"Shelve Changes... "という変更の待避機能にも使われます。先ほどの例で作成したチェンジリストを、とある理由でいったん破棄したい場面に遭遇したとしましょう。でも、もしかしたら、それも取りやめて破棄前に戻す可能性もある……そんな場面です。GitやMercurialを使っているのであれば「git stash
やhg shelve
を使えばいいや」と思いますが、Subversionならどうでしょうか?
特定のバージョン管理システムに依存せず、修正の待避を行うのが、この"Shelve Changes... "です。使い方は簡単で、待避したいチェンジリストを選択してコンテキストメニューから"Shelve Changes... "を実行するだけです。
図12 "Shelve Changes..."の実行例(クリックすると動きがわかります)
コマンドを実行すると「Commit Changesダイアログ」によく似た「Shelve Changesダイアログ」が表示されます。コミット欄に任意の文言を入力して「Shelve Changes」ボタンを押して下さい(通常、コミット欄にはチェンジリスト名がプリセットしてあると思います) 。すると「Changesツールウィンドウ / Shelveタブ」にその内容が待避されます。待避した登録名が先ほど入力したコミットメッセージになるので、メッセージ欄とは言え、ほどほどの文言にしておかないと、この画面がとても見づらくなります。
この待避機能の正体はパッチ(patch)です。待避した変更内容をまた元に戻したい場合は、「 Changesツールウィンドウ / Shelveタブ」で対象を選び、コンテキストメニューから "Unshelve Changes " を実行します。
図13 待避したチェンジリストを戻す
復帰するコマンドは "Unshelve Changes " の他に "Unshelve... " の2つがあります。前者は復帰すると待避していた変更内容はShelveタブから消えますが、後者は復帰しても「Shelveタブ」に残ります。
GitやMercurialといったDVCSの普及によって、さほど珍しい機能ではなくなりましたが、その前は大変特徴的な機能だったんですよ。なお、チェンジリストの定義情報は .idea/workspace.xml
に待避した変更内容の実体は <AS_CONFIG>/shelf/<待避名>.patch
にそれぞれ保存されます。どちらもバージョン管理システムに登録する対象ではありません。