Android SDKのコマンドラインを使ったAndroidアプリプロジェクトの作成方法を記しておきます。しばらく離れているとすぐに忘れるので備忘録として(というかこうして書くことでより記憶に定着させるため)。
前提: SDK, JDK, ant等必要な物をインストールしてパスを通してあること
プロジェクトの作成
android --help create project
で、ヘルプが出るので参考に。
android※1 create project -n MyAwesomeApp -t 10※2 -p ./MyAwesomeApp※3 -k com.example.my_awesome_app -a MyAwesomeApp※4
- ※1: Cygwin等からはandroid.batとするとよい。
- ※2: -tの値(target ID)は環境によって異なる? android list targets で表示される。
- ※3: カレントディレクトリへ作るなら単にピリオドのみでOK。
- ※4: Activity名。デフォルトでアプリアイコンの下に表示される名前になる。
参考: http://developer.android.com/tools/help/android.html
コンパイルは次のようにする。
cd MyAwesomeApp
ant debug
インストールはAVDか端末を接続した上で ant debug install
とする。
バージョン管理に入れる(Subversionやgit等)
バージョン管理では次のファイルを無視する(.gitignore等)。
- local.properties
- bin
- gen
- libs
- obj (NDK使用時)
バージョン管理から取り出したときの作業
リポドシリから取り出したときはlocal.propertiesが無いので生成する必要がある。
cd MyAwesomeApp
android update project -p .
キーストアの情報が必要ならlocal.propertiesへ追記する。
キーの生成方法
キーの生成は次のようにする。(keytoolはJDKのbinの中)
keytool -genkey -v -keystore my_awesome_app.keystore -alias my_awesome_app -keyalg RSA -keysize 2048 -validity 10000
local.propertiesにキーの情報を追加する。
key.store=my_awesome_app.keystore key.alias=my_awesome_app
次のようにしてリリースビルドできるようになるはず。
cd MyAwesomeApp
ant release
参考: http://developer.android.com/tools/publishing/app-signing.html
NDK
NDKを使いたい場合はjniディレクトリを作る。NDKのsamplesディレクトリを参考にすると良い。
プロジェクトディレクトリ下にjniディレクトリを作り、次のファイルを配置する。
- Android.mk
- Application.mk
- *.cpp, *.h等
ビルドはプロジェクトディレクトリトップで ndk-build
とし、成功したら、普通に ant debug
等。(参考: https://developer.android.com/ndk/guides/ndk-build.html)
AndroidManifest.xml は必要に応じて修正すること。特にNativeActivityを使う場合は修正が必要。
各ファイルの例を次に記す。(android-ndk-r10e時点。バージョンによってオプションは変わっていくかも?)
jni/Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_CPP_FEATURES += exceptions LOCAL_CPP_FEATURES += rtti LOCAL_MODULE := my-awesome-app-jni LOCAL_SRC_FILES := my-awesome-app-jni.cpp include $(BUILD_SHARED_LIBRARY) # include $(BUILD_EXECUTABLE) ←main()から実行する場合はこちら。
例外やRTTIのないC++なんて98年以前の感じですね。今更耐えられないので有効。(r10e現在デフォルト無効)
現在のバージョンではC++11はデフォルトで使えるらしいです。ライブラリはまた別の話ですが。
参考: https://developer.android.com/ndk/guides/android_mk.html
jni/Application.mk
APP_ABI := all APP_STL := c++_static
stlport(stlport_static)にはstd::to_stringが無かったのでclangのライブラリ(c++_static)を指定しました。
参考: https://developer.android.com/ndk/guides/application_mk.html
jni/my-awesome-app-jni.cpp
#include <jni.h> #include <string> extern "C" JNIEXPORT jstring JNICALL Java_com_example_my_1awesome_1app_MyAwesomeApp_nativeExampleFun( JNIEnv *env, jobject thisj, jstring exampleStr, int exampleInt, jobject exampleObj) { struct UTFChars { JNIEnv *env; jstring str; const char *chars; UTFChars(JNIEnv *env, jstring str):env(env), str(str), chars(env->GetStringUTFChars(str, nullptr)){} ~UTFChars(){if(chars){env->ReleaseStringUTFChars(str, chars);}} const char *get() const {return chars;} }; const std::string result = UTFChars(env, exampleStr).get() + std::to_string(exampleInt); return env->NewStringUTF(result.c_str()); }
関数名はパッケージ名やクラス名に合わせる。パッケージ名に_(アンダースコア)が入っているときは_の後に1が必要なので注意。_のままだとランタイムでエラーになる。
JNIに詳しくないんですが、こういうことをするための文字列ライブラリってないんですか?
src/com/example/my_awesome_app/MyAwesomeApp.java
//...略... import android.graphics.Bitmap; import android.widget.Toast; public class MyAwesomeApp extends Activity { //...略... // ネイティブ関数の宣言 static { System.loadLibrary("my-awesome-app-jni"); //LOCAL_MODULEで指定した名前 } native String nativeExampleFun(String exampleStr, int exampleInt, Bitmap exampleObj); //...略... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // ネイティブ関数を呼び出してみる String result = nativeExampleFun("test", 123, null); Toast.makeText(this, result, Toast.LENGTH_LONG).show(); //test123と表示される } }
AndroidManifest.xml (NativeActivity使用時の例)
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.my_awesome_app" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="14" /><!--←SDKのバージョン--> <uses-feature android:glEsVersion="0x00020000"></uses-feature><!--←OpenGL ESを使う場合、そのバージョン--> <application android:label="@string/app_name" android:icon="@drawable/ic_launcher" android:hasCode="false"><!--←Javaのコードを使わない場合はhasCodeをfalseにすること--> <activity android:name="android.app.NativeActivity" android:label="@string/app_name" android:configChanges="orientation|keyboardHidden"><!-- nameはNativeActivityを使うならこの値で固定。configChangesは端末回転時にActivityを破棄しない設定らしいけど、APIレベルによっては効かないらしい? --> <meta-data android:name="android.app.lib_name" android:value="my-awesome-app-jni" /><!-- ←valueはAndroid.mkのLOCAL_MODULEで指定したモジュール名 --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>