Android
Eclipse
AndroidStudio

EclipseからAndroidStudioへの移行手順まとめ

More than 3 years have passed since last update.

AndroidStudio正式版がリリースしました。Eclipse+ADTはオワコンという風潮がより一層強まってきたので、自分がEclipseで開発していたプロジェクトをAndroidStudioに移行した時の手順を残しておこうと思います。



移行するプロジェクトの状態


  • コードはgitで管理。

  • クラス数は300個くらい。

  • mavenもgradleも不使用。ライブラリはlibrary/にまるごと入れて、Eclipseでプロジェクトを作ったあとインポート。

  • lib、library合わせて依存ライブラリの数は10個以上。

git管理はしてるものの、クラスがそれなりに多いのに依存関係ぐちゃぐちゃで、EventBusとか便利ライブラリ入れていきたいのにちょっと戸惑うなぁという感じでした。「俺もgradleでライブラリ管理したりコンソールから環境ごとにビルドしたりしたいよ!」という思いを胸に秘めながら開発していたわけです。


AndroidStudioのインストール

まずはAndroidStudioをインストールします。起動してAndroid SDKのパスを設定すれば準備OKです。


プロジェクトの新規作成

EclipseからAndroidStudioへのインポートは、Eclipseのエクスポート機能を使えば簡単に行えます。詳しくは公式のMigrating to AndroidStudioを参考にしてください。

しかし、実際に本番のプロジェクトでやってみると、エラーが出まくってうまくいきませんでした。ライブラリたくさん使った大きめのプロジェクトだとうまくいかないこともあるようです。

また、プロジェクト構成はそのままで、gradleのプロジェクト構成になっていません。これだと結局プロダクトフレーバーといったAndroidStudioの利点が享受できません。

いっそのことgradleプロジェクトを新規作成してbuild.gradleを自分で頑張って書いてコードとリソースをコピーした方が早そうだったので、新規作成することにしました。新規作成はAndroidStudioのダイアログにしたがっていけば迷わずできました。

なんかよくわからない変な感じになったらアンインストールしてやり直した方がいいかもしれません。AndroidStudio完全アンインストールマニュアル


build.gradleを記述

ここが一番の鬼門です。手順としてはこんな感じです。


  1. 依存ライブラリをGoogleで調べてgradleの記述方法を見つけて記述

  2. gradle syncしてみる

  3. エラーが出たらエラー解消、出なければインポートしたライブラリが正しいかを確かめる

例えば、Aviaryというライブラリのgradleの記述を『aviary sdk gradle』でGoogleで調べてみると、公式ページにgradleサポートの情報が載っています。サンプルを落としてReadmeを見ると、gradleの記述方法が書いてありました。Aviaryの場合はこんな感じです。


build.gradle

dependencies {

compile ('com.aviary.android.feather.sdk:aviary-sdk:3.4.3.351')
}

syncする時は、AndroidStudio上部のバーのボタンをクリックします。

android_studio_migration3.png

エラーが出たら、メッセージにエラーが表示されます。

android_studio_migration4.png

基本はこの作業を繰り返していくだけなんですが、たぶん色々エラーにハマるので気合いで乗り切りましょう。

自分がハマったのはこのあたりです。もしかしたら参考になるかもしれません。

結局出来たbuild.gradleはこんな感じです。(もっといい書き方あったら教えてほしいです)


build.gradle

apply plugin: 'com.android.application'

// load release properties
Properties props = new Properties()
if (rootProject.file("release.properties").exists()) {
props.load(new FileInputStream(rootProject.file("release.properties")))
} else {
println "Please create release.properties in project root."
}

android {
compileSdkVersion 19
buildToolsVersion '19.1.0'

defaultConfig {
applicationId 'com.konifar'
minSdkVersion 10
targetSdkVersion 19
versionCode 1
versionName '1.0.0'
}
productFlavors {
development {
applicationId 'com.konifar'
}
staging {
applicationId 'com.konifar.staging'
}
production {
applicationId 'com.konifar'
}
}

signingConfigs {
release {
storeFile rootProject.file("konifar.keystore")
storePassword props.storePassword
keyAlias props.keyAlias
keyPassword props.keyPassword
}
}
buildTypes {
debug {
// gradle 0.14.+以降だとminifyEnabled
runProguard false
}
release {
// gradle 0.14.+以降だとminifyEnabled
runProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
lintOptions {
checkReleaseBuilds false
abortOnError false
}
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
}
dexOptions {
jumboMode true
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':libraries:facebook')
compile ('com.android.support:appcompat-v7:19.+') {
exclude module: 'support-v4'
}
compile ('com.nostra13.universalimageloader:universal-image-loader:1.9.1') {
exclude module: 'support-v4'
}
compile ('com.mobeta.android.dslv:drag-sort-listview:0.6.1') {
exclude module: 'support-v4'
}
compile ('com.jakewharton:butterknife:4.0.1')
compile 'de.greenrobot:eventbus:2.2.1'
// - 略 -
}



コードとリソースをコピー

gradle syncして依存ライブラリをダウンロードできたら、Eclipseのプロジェクトのコードとリソースを新しいgradleプロジェクトにコピーします。gradleプロジェクトだとapp/src/main/java/にコードを配置します。リソースはapp/src/main/res/です。

これはただコピーするだけで大丈夫でした。lintの設定が違う場合は少しエラーが表示されるかもしれません。build.gradleでインポートしたライブラリが間違っていた場合はここでエラーが大量発生するので、頑張ってエラーを解消しましょう。


ビルドして実行

いよいよビルドして実行です。ここでも色々ハマるポイントはあったので、下記に大体まとめてあります。


Proguardを記述

ビルド時にProguardを使うには、build.gradleのbuildTypesにminifyEnabled trueを記述します。(gradle0.13.+以下だとrunProguard trueです)


build.gradle

buildTypes {

debug {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}

app/proguard-rules.proには、proguardの設定を記述します。

何も指定しないと難読化してはいけないコードまで難読化されてしまって、まったく動かなくなります。keepオプションなどを使っていい感じに除外していく必要があります。例えば、gsonを使う場合は実行時にこんなエラーが出てしまいます。Proguardを使っている時のgsonのエラー

最終的に下記のようなproguard-rules.proを書きました。


proguard-rules.pro

-dontwarn com.konifar.**

-dontwarn org.apache.**
-dontwarn javax.**
-dontwarn butterknife.**
-dontwarn com.squareup.okhttp.**

-keep class com.konifar.** { *; }
-keep interface com.konifar.** { *; }
-keep class com.facebook.** { *; }
-keep interface com.facebook.** { *; }
-keep class org.apache.** { *; }
-keep interface com.google.** { *; }
-keep class com.google.** { *; }
-keep interface java.** { *; }
-keep class java.** { *; }
-keep interface org.json.** { *; }
-keep class org.json.** { *; }
-keep interface android.** { *; }
-keep class android.** { *; }
-keep interface com.aviary.** { *; }
-keep class com.aviary.** { *; }

-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose
-dump class_files.txt
-printseeds seeds.txt
-printusage unused.txt
-printmapping mapping.txt
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

-allowaccessmodification
-keepattributes *Annotation*
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-repackageclasses ''

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-dontnote com.android.vending.licensing.ILicensingService

# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}

# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames class * {
native <methods>;
}

-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}

# Preserve static fields of inner classes of R classes that might be accessed
# through introspection.
-keepclassmembers class **.R$* {
public static <fields>;
}

# Preserve the special static methods that are required in all enumeration classes.
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}

-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}

-keepattributes Signature

# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }


keepオプションなんかはまだまだ超適当です。 本当はもっとちゃんと書かないとダメです。他のプロジェクトのproguardファイルとか見せてもらいたいです。Android Annotationsを使うと、アノテーションでもっと綺麗に記述できるかもしれません。


変更をgit push

うまくいけばプロジェクトを実行できるはずですが、コードのディレクトリなどがガラッと変わってしまうことでgitの履歴が消えてしまうのは嫌ですよね。

なので、今まで作った構成を参考に元のgit プロジェクトを同じ構成に作り直すことにしました。具体的にはgit mvコマンドを使ってコードとリソースのコピー作業をやり直します。git mvを使うと、変更履歴を保持したままファイル位置を変更することができます。

gitプロジェクトを同じ構成に変更できたら、AndroidStudioにインポートして動くかどうか見てみましょう。


ざっくりですが、こんな流れで移行しました。これから移行を検討している方々の参考になれば幸いです。