はじめに
この記事は Android Advent Calendar 2019 の6日目です!
普段、Androidアプリケーションをどの言語どのフレームワークetc..を使って開発していますか?
自分は Android Studio + Java や Unity + C# で開発することが多いです
思えば自分が触ったことが無いフレームワークはたくさんありますが、自分が開発したいもの合わせて、よりベストな環境を選んでおきたい身としてはいろんなフレームワーク、言語を知って触っておくに越したことは無いのはエンジニアとしては当然だと思ってます。
なので、いろんなフレームワークを使って 同じ動作をする Androidアプリを作成します!
TL;DR
Androidアプリケーション開発のフレームワーク一覧
| フレームワーク | 言語 | 公式ページ | IDE | 一言特徴 | 実装済(死に戻り) |
|---|---|---|---|---|---|
| Android Studio | Java/Kotlin/C++ | https://developer.android.com/studio/ | Android Studio | ネイティブアプリケーション | ✅ |
| Unity | C# | https://unity3d.com/jp/unity | Unity Editor | ゲームエンジン | ✅ |
| Processing | Java | https://processing.org/ | Processing | グラフィックフレームワーク | ✅ |
| openFrameworks | C++ | https://openframeworks.cc/ | Android Studio | グラフィックフレームワーク | ✅ |
| Cordova | HTML5+JavaScript+CSS | https://cordova.apache.org/ | Visual Studio(Win) | クロスプラットフォーム | ✅ |
| React Native | Javascript/TypeScript | https://facebook.github.io/react-native/ | 特になし | クロスプラットフォーム | ✅ |
| Xamarin.Form | C#/F# | https://dotnet.microsoft.com/apps/xamarin | Visual Studio | クロスプラットフォーム | ✅ |
| Xamarin.Android | C#/F# | https://dotnet.microsoft.com/apps/xamarin | Visual Studio | ネイティブアプリケーション | ✅ |
| Unreal Engine | C++/UnrealScript | https://www.unrealengine.com/ | Unreal Editor | ゲームエンジン | ❌ |
| Flutter | Dart | https://flutter.dev/ | Android Studio | クロスプラットフォーム | ❌ |
| Cocos2d-x | C++/Lua/JavaScript/TypeScript | https://www.cocos.com/en/ | Cocos Creator | ゲームエンジン | ❌ |
| Monaca | HTML5+JavaScript | https://ja.monaca.io/ | ブラウザ/Monaca Localkit | クロスプラットフォーム | ❌ |
| DXライブラリ | C++ | https://dxlib.xsrv.jp/ | Android Studio | ゲームエンジン | ❌ |
| Qt | C++ | https://www.qt.io/ | Qt Creator IDE | クロスプラットフォーム | ❌ |
| ionic | JavaScript | https://ionicframework.com/ | Ionic Studio | クロスプラットフォーム | ❌ |
| Titanium | JavaScript | https://www.appcelerator.com/Titanium/ | Appcelerator Studio | クロスプラットフォーム | ❌ |
| NativeScript | TypeScript/JavaScript | https://www.nativescript.org/ | VSCode/WebStorm | クロスプラットフォーム | ❌ |
| Weex | JavaScript | https://weex.apache.org/ | 特になし | クロスプラットフォーム | ❌ |
| meteor | JavaScript | https://www.meteor.com/ | 特になし | クロスプラットフォーム | ❌ |
| Vue Native | JavaScript | https://vue-native.io/ | 特になし | クロスプラットフォーム | ❌ |
| Defold | Lua | https://defold.com/ | Defold editor | ゲームエンジン | ❌ |
| Godot | GDScript | https://godotengine.org/ | Godot Engine | ゲームエンジン | ❌ |
| SCADE | Swift | https://www.scade.io/ | Scade IDE | クロスプラットフォーム | ❌ |
| Kotlin Native | Kotlin | https://kotlinlang.org/docs/reference/native-overview.html | Android Studio | クロスプラットフォーム | ❌ |
| AndEngine | Java | http://www.andengine.org/ | IntelliJ IDEA | ゲームエンジン | ❌ |
作るもの
画面にただHello Worldと表示しても面白くないので、ボタンを押すと背景の色が変わるアプリを作ります。
UI要素がどのように設置できるか ボタンイベントをどのように取得できるか Viewはどのように描画できるか 、という点をみれるので良いチュートリアルだと思います

Android Studio
- Google謹製のAndroidプラットフォーム向けアプリ開発用の統合開発環境
- この環境が出るまでは、Eclipse + ADT (Android Developer Tools)でAndroidアプリの開発が行われていた
- なにより公式、ドキュメントもツールも揃っている
- ネイティブアプリケーションを作りたいなら王道
Java
まずは、JavaでAndroidアプリの作成を行います
-
Android Studioのインストール(説明は割愛します
-
Android Studioを立ち上げて、今回は新しくアプリを作成するので
Start a new Android Studio projectを選びます。最近開いたプロジェクトは左に表示されています

-
必要な情報を入力します。
Nameはアプリ名を入れます。Save Locationはプロジェクトを設置するディレクトリパスです。(既にプロジェクトが存在する場合はalready exists...と警告してくれます

Finishを押すとAndroidアプリのプロジェクトが生成されます
生成されたファイルはざっと以下の感じになります
AndroidStuidoJava
├── app
│ ├── build.gradle
│ └── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── jp
│ │ └── cha84rakanal
│ │ └── hellotogglecolor_studio_java
│ │ └── MainActivity.java
│ └── res
│ ├── drawable
│ │ └── ic_launcher_background.xml
│ ├── layout
│ │ └── activity_main.xml
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── local.properties
└── settings.gradle
4.プロジェクトが生成されたらボタン実装する前に兎にも角にも一旦起動します。起動には上部の緑の▶マークを押すか、Ctrl + Rを押します。その後、インストールするデバイスを選んでOKを押すと、ビルドされインストールされ起動します。


ボタンを実装
アプリが動くことを確認できたらボダンを実装していきます
res/layout/activity_main.xml を開いて次の内容に変更します。するとボタンが画面中央に配置された画面が構成されます
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Hello World!" />
</RelativeLayout>
ボタンがクリックしたことを検知
設置したボタンはこのままではただのボタンなので、プログラムでボタンが押されたことを確認できるようにします。
MainActivity.java に引数にViewクラスを1個を持ち返り値voidの適当なメソッドを作成します
package jp.cha84rakanal.hellotogglecolor_studio_java;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
void onButtonClick(View v){
Log.v(MainActivity.class.getSimpleName(),"onButtonClick");
}
}
Log.v はログを出力するメソッドでボタンを押すと onButtonClickとログに表示されます
ボタンを押したらどのメソッドを実行するか、今はわからないので、 activity_main.xmlで指定しますButton 要素に android:onClickプロパティを追加して作成した適当なメソッド名を渡します
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:onClick="onButtonClick"
android:text="Hello World!" />
これで、ボタンを押すとログにonButtonClickと表示するアプリになりました
ログはターミナルで、adb logcatコマンドを実行するか、Android StudioのLogcatを使います
Logのタグに MainActivity.class.getSimpleName() を指定しているのでフィルターにMainActivityを打つと、onButtonClickのログだけを見れます
※ターミナルでのフィルタリング adb logcat -s MainActivity:*

背景の色を変更
残りは背景の色を変えるだけです
activity_main.xmlのRelativeLayout 要素に android:backgroundプロパティを追加して色を指定します。色の指定は#[透明度00~FF][赤00~FF][緑00~FF][青00~FF]です
MainActivity.javaから参照できるように、IDをつけておきます
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/back"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFF0000"
tools:context=".MainActivity">
MainActivity.javaでは、findViewByIdを使って、先程IDをつけた要素を取得して setBackgroundColorを使って色を変える部分を実装します。
package jp.cha84rakanal.hellotogglecolor_studio_java;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends Activity {
private boolean mToggle = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
void onButtonClick(View v){
Log.v(MainActivity.class.getSimpleName(),"onButtonClick");
mToggle = !mToggle;
findViewById(R.id.back).setBackgroundColor( mToggle? 0xFFFF0000 : 0xFF0000FF);
}
}
これでボタンを押すと 赤から青、青から赤に色が変わるアプリができました!

Kotlin
引き続いて、Android StudioでKotlinを使って同じアプリを作っていきます
Android Studioでは、プロジェクトの中に モジュール という単位で、アプリのプロジェクトやライブラリなどのプロジェクトが存在します。(デフォルトだとプロジェクトを作成した段階でのアプリのモジュール名は app )
次は新しくプロジェクトを作らずに現在のプロジェクトにKotlinのアプリのモジュールを追加します
-
File > New > New Module... を開き、アプリなので
Phone & Tablet Moduleを選択します

-
Source Languageを
Kotlinにします。選択するだけでJavaもKotlinも使えるのはAndroid Studio素晴らしい!

Finishを押すとAndroidアプリのモジュールが生成されます
先程作ったプロジェクトの中に、hellotogglecolor_studio_kotlin ディレクトリができてると思います
AndroidStuidoJava
├── app <-- さっきのJavaでのアプリ
├── hellotogglecolor_studio_kotlin <-- これから作るKotlinのアプリ
├── build.gradle
├── gradle.properties
├── local.properties
└── settings.gradle
ただ色が変わるだけのアプリでは、JavaとKotlinでの書き方がちょっと違うぐらいなので、別の方法で実装すすめていきます
ボタンを実装
すべてMainActivity.ktで実装します
MainActivityにおけるルートViewはConstraintLayoutでその子にButtonがあり、センタリングは上下左右の制約で行います。
制約をKotlinで書くと凄い大変なので、極力XMLでレイアウトを組むのが良さそうです...
package jp.cha84rakanal.hellotogglecolor_studio_kotlin
import android.app.Activity
import android.os.Bundle
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import android.widget.Button
import android.view.View
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val cLayout = ConstraintLayout(this)
val button = Button(this)
cLayout.addView(button)
val viewId = View.generateViewId()
button.id = viewId
button.text = "Hello World!"
val constraintSet = ConstraintSet()
constraintSet.clone(cLayout)
// android:layout_width="wrap_content"
constraintSet.constrainHeight(button.id,
ConstraintSet.WRAP_CONTENT)
//android:layout_height="wrap_content"
constraintSet.constrainWidth(button.id,
ConstraintSet.WRAP_CONTENT)
// app:layout_constraintBottom_toBottomOf="parent"
constraintSet.connect(
button.id,
ConstraintSet.BOTTOM,
ConstraintSet.PARENT_ID,
ConstraintSet.BOTTOM,
0)
// app:layout_constraintLeft_toLeftOf="parent"
constraintSet.connect(
button.id,
ConstraintSet.LEFT,
ConstraintSet.PARENT_ID,
ConstraintSet.LEFT,
0)
// app:layout_constraintRight_toRightOf="parent"
constraintSet.connect(
button.id,
ConstraintSet.RIGHT,
ConstraintSet.PARENT_ID,
ConstraintSet.RIGHT,
0)
// app:layout_constraintTop_toTopOf="parent"
constraintSet.connect(
button.id,
ConstraintSet.TOP,
ConstraintSet.PARENT_ID,
ConstraintSet.TOP,
0)
constraintSet.applyTo(cLayout)
// ConstraintLayout set on ContentView
setContentView(cLayout)
}
}
これでボタンが中央に実装されました。
ボタンがクリックしたことを検知
ボタンのクリック検知にはOnClickListenerを使います
onCreateメソッドの中のbuttonの定義の後に次のコードを加えます
button.setOnClickListener {
Log.v(MainActivity::class.java.simpleName, "onButtonClick")
}
これで、ボタンを押すとログにonButtonClickと表示するアプリになりました
背景の色を変更
背景色だけはJavaとほとんど変わらず、setBackgroundColorを使えばできます
Kotlinでは三項演算子がなく、ifを式として扱えるのは特徴的な気がします
package jp.cha84rakanal.hellotogglecolor_studio_kotlin
import android.app.Activity
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import android.widget.Button
import android.view.View
class MainActivity : Activity() {
private var mToggle = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val cLayout = ConstraintLayout(this)
cLayout.setBackgroundColor(Color.RED)
val button = Button(this)
cLayout.addView(button)
val viewId = View.generateViewId()
button.id = viewId
button.text = "Hello World!"
button.setOnClickListener {
Log.v(MainActivity::class.java.simpleName, "onButtonClick")
mToggle = !mToggle
cLayout.setBackgroundColor(if(mToggle) Color.RED else Color.BLUE)
}
見た目は、Javaで作られたのと変わらなかったです...
C++
Android Studioで使える言語は、Java Kotlin だけではありません。 NDK(Native Development Kit)を利用すれば C/C++ でも開発ができます
いままでJava/Kotlinで開発していた Activity をまるごと実装することができるので、今回はNativeActivityを使って、目的のアプリをつくります。
-
NDKを使える環境をインストールします。 Tools > SDK Managerを使って、NDK/CMakeをインストールします。(File > Project Structureからもダウンロードできます)
File > Project Structureを開いて、Android NDK LocationにNDKをインストールしたディレクトリパスが指定されていればOKです

-
一からプロジェクトを作成すると大変なので、既にできているサンプルを改造します。
File > New > Import Module...を開き、検索窓にNativeと打ち込みます。するとサンプルの一覧にNdk > Native Activityとあるのでそれを選択します。

Finish を押すとサンプルがGitHubからクローンされます。
- 自動でプロジェクトが開くので、
File > Sync Project with Gradle Filesを押します。それが終わったら兎にも角にもビルドしてアプリをRUNしましょう
ボタンを実装
これからボタンを実装していきます。C++だけで実装されたアプリのソースは、app/src/main/cpp/main.cppだけなので、ボタンも描画もここに実装していくしかなさそうです。しかし、TeapotのNDKサンプルでは、Java側でUIが書かれているので参考にしていきます。
まずは、Java側のActivityを実装していきます。
app/src/mainにjavaディレクトリを作成して、javaディレクトリにActivityを作成します。javaディレクトリを右クリックして New > Activity > Empty Activityを選択します。パッケージ名はここではjp.cha84rakanal.hellotogglecolor_studio_c_plusplusにします。
MainActivity.javaとactivity_main.xmlが自動生成されて、ディレクトリの構造は以下のようになります。
main
├── AndroidManifest.xml
├── cpp
│ ├── CMakeLists.txt
│ └── main.cpp
├── java
│ └── jp
│ └── cha84rakanal
│ └── hellotogglecolor_studio_c_plusplus
│ └── MainActivity.java
└── res
├── layout
│ └── activity_main.xml
├── mipmap-hdpi
│ └── ic_launcher.png
├── mipmap-mdpi
│ └── ic_launcher.png
├── mipmap-xhdpi
│ └── ic_launcher.png
├── mipmap-xxhdpi
│ └── ic_launcher.png
└── values
└── strings.xml
自動生成されてMainActivity.javaはAppCompatActivityクラスを継承していますが、C++のActivityと共存させるためにNativeActivityクラスを継承します。 MainActivity.javaの内容は次のようにして、アプリが起動したらログにin onCreateと出るようにします。
package jp.cha84rakanal.hellotogglecolor_studio_c_plusplus;
import android.app.NativeActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends NativeActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v("java_code","in onCreate");
}
}
このままでは、MainActivity.javaが起動しないので、AndroidManifest.xmlを編集しておきます。application要素のandroid:hasCode="false"を消して、activity要素のandroid:nameを先程作成したActivityの名前にします。
<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jp.cha84rakanal.hellotogglecolor_studio_c_plusplus"
android:versionCode="1"
android:versionName="1.0">
<!-- This .apk has no Java code itself, so set hasCode to false. -->
<application
android:allowBackup="false"
android:fullBackupContent="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name">
<!-- Our activity is the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
<activity android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden">
<!-- Tell NativeActivity the name of our .so -->
<meta-data android:name="android.app.lib_name"
android:value="native-activity" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<!-- END_INCLUDE(manifest) -->
これでアプリをビルド/RUNするとC++で作成したmain.cppとJavaで作成したMainActivity.javaが起動していることを確認できると思います。
次は、XMLで定義したViewを表示していけるようにします。サンプルをみると、onCreateではsetContentViewをしておらず、showUIというメソッドでUIを表示しているみたいです。なのでまずはMainActivityにshowUIメソッドを実装します。
MainActivity activity;
PopupWindow popupWindow;
// Our popup window, you will call it from your C/C++ code later
@SuppressLint("InflateParams")
public void showUI() {
Log.v("java_code","showui Called");
if( popupWindow != null )
return;
activity = this;
this.runOnUiThread(()->{
LayoutInflater layoutInflater
= (LayoutInflater)getBaseContext()
.getSystemService(LAYOUT_INFLATER_SERVICE);
View popupView = layoutInflater.inflate(R.layout.activity_main, null);
popupWindow = new PopupWindow(
popupView,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT);
LinearLayout mainLayout = new LinearLayout(activity);
ViewGroup.MarginLayoutParams params = new ViewGroup.MarginLayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
params.setMargins(0, 0, 0, 0);
activity.setContentView(mainLayout, params);
// Show our UI over NativeActivity window
popupWindow.showAtLocation(mainLayout, Gravity.CENTER, 0, 0);
popupWindow.update();
});
}
layoutInflater.inflateでR.layout.activity_mainをしているので、activity_main.xmlを次のように変更しておきます
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Hello World!" />
</RelativeLayout>
これで、ビルド/RUNで画面の真ん中にHello World!!と表示されるわけではありません。showUIメソッドがどこからも呼び出されていません。じゃあどこから呼び出すのかというとC++で実装しているNativeActivitymain.cppから呼び出します。 main.cppに次の関数を加えます。実行中のVMにアタッチして、showUIをC++側から呼び出せるようにします。
void showUI(struct engine* engine) {
JNIEnv* jni;
engine->app->activity->vm->AttachCurrentThread(&jni, NULL);
// Default class retrieval
jclass clazz = jni->GetObjectClass(engine->app->activity->clazz);
jmethodID methodID = jni->GetMethodID(clazz, "showUI", "()V");
jni->CallVoidMethod(engine->app->activity->clazz, methodID);
engine->app->activity->vm->DetachCurrentThread();
return;
}
そして、engine_init_display(struct engine* engine)の一番最後で、加えたshowUI(struct engine* engine)を呼び出します。
/**
* Initialize an EGL context for the current display.
*/
static int engine_init_display(struct engine* engine) {
// initialize OpenGL ES and EGL
//-----省略-----//
// Initialize GL state.
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glEnable(GL_CULL_FACE);
glShadeModel(GL_SMOOTH);
glDisable(GL_DEPTH_TEST);
ShowUI(engine); //<--さっき追加した関数
return 0;
}
これで、NativeActivityでの画面の初期化が終わったあとに、Java側でViewをオーバーレイして表示します。
これで、背景はC++でUIがJavaの状態で画面中央にHello Worldと表示されました!
ここまで来るとボタンの設置は簡単です。activity_main.xmlを次のように変更するだけでボタンを実装できます。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Hello World!" />
</RelativeLayout>
ボタンがクリックしたことを検知
Java側でボタンがクリックされたことを検知することは簡単ですね。ボタンにbuttonとIDをふっているので、setOnClickListenerメソッドを使っておしまいです。
popupView.findViewById(R.id.button).setOnClickListener(v -> {
Log.e("java_code","ButtonClicked Called");
});
Java側では検知できましたが、C++側は何もわかりません。背景の描画を担当しているのは、C++側なので、JavaからC++の関数を叩いて上げる必要があります。
まずmain.cppにJavaから呼ばれる関数を作成します。命名規則は Java_{Package Name}_{呼び出し元クラス名}_{メソッド名} です。引数や戻り値などついてもろもろありますがここでは説明ません。詳しいことはandroid jniとかでググってください。 main.cpp に次のような関数を追加します。
extern "C"
JNIEXPORT void JNICALL
Java_jp_cha84rakanal_hellotogglecolor_1studio_1c_1plusplus_MainActivity_toggle(JNIEnv * env, jobject obj){
LOGW("called in native");
}
次に、MainActivityから呼び出せるようにします。System.loadLibraryメソッドの引数に、native-activityを指定して、Java側でC++の関数を使えるようにロードします。あとは、C++に実装した関数を、 public native {戻り値の型} {関数名}(); のようにJavaで定義します。そうすることで、Javaメソッドのように普通にC++の関数を呼び出せます。
public class MainActivity extends NativeActivity {
MainActivity activity;
PopupWindow popupWindow;
static {
System.loadLibrary("native-activity");
}
public native void toggle();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v("java_code","in onCreate");
}
//----省略----//
popupView.findViewById(R.id.button).setOnClickListener(v -> {
Log.e("java_code","ButtonClicked Called");
toggle();
});
//----省略----//
これで、ボタンをを押すと、Java側で、ButtonClicked Calledとログが出力され、C++でcalled in native とログが出力されます。
これで、C++でもボタンがクリックされたことわかりました。
背景の色を変更
背景の描画はmain.cppのengine_draw_frame(struct engine* engine)で行われています。実装をみると、EGL/OpenGLESを使って描画されているのがわかります。とすると、単に背景を塗りつぶすだけならglClearColorで良さそうです。なのでmain.cppを次のように変更していきます。
static int toggle_count = 0;
extern "C"
JNIEXPORT void JNICALL
Java_jp_cha84rakanal_hellotogglecolor_1studio_1c_1plusplus_MainActivity_toggle(JNIEnv * env, jobject obj){
LOGW("called in native");
toggle_count++;
}
/**
* Just the current frame in the display.
*/
static void engine_draw_frame(struct engine* engine) {
if (engine->display == NULL) {
// No display.
return;
}
if(toggle_count%2 == 0){
// Just fill the screen with a color.
glClearColor(1,0,0,1);
}else{
glClearColor(0,0,1,1);
}
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(engine->display, engine->surface);
}
※engine.animatingが1じゃないとengine_draw_frame(struct engine* engine)が呼ばれないので注意
とりあえずこれでC++??でも同じアプリができました!
Nativeで動いてるとなんだかよくわからんけど速いって気持ちになっていいですね。Android NDKも色々できることがあるので今後まとめて行けたらと思います。
Unity
- ゲーム開発エンジン
- クロスプラットフォームの開発が可能
- アセットと呼ばれる素材やツールが便利
- プラグインという形でOS固有のAPIを呼び出すことも可能
それでは、Unityを使ってAndroidアプリの作成をおこなっていきます!
-
Unity Editor/Unity Hubのインストール(説明は割愛します。
Android Build Supportを入れるのを忘れずに)
これでUnity Editorの画面が表示されます。
兎にも角にもこの状態でAndroid上で動かして、エラーとか起こらないことを確認しましょう。
File > Build Settingsを開くと、 PC Mac & Linux Standalone にUnityマークがあるので、Androidを選択してSwitch Platform を押します。
そうすると Android にUnityマークがついて、Build and Runを押せるので押します。ファイルダイアログが出るので、適当にBuild ディレクトリを作ってSave を押します。そうすると、Unity内部でビルドがはしってAPKが生成され自動でインストールされ実行されます。

Unityのロゴが表示されて、何もない暗いブルーが表示されます。
ボタンを実装
それでは、ボタンを実装していきます。Unityではシーンにコンポーネントを設置して、ゲームやアプリを作っていきます。
Hierarchyウィンドウで右クリックを押してUI > Buttonをクリックでボタンが設置されます。

これでBuild and Runをするとなんとなく中央から左下に向かう途中あたりにボタンが来ます。

位置を真ん中にして押しやすいようにもうちょっと大きくしようと思います。
Hierarchyに表示されているCanvasをクリックすると右側のInspectorに、Canvasに設定されてるコンポーネントの情報が表示されます。
Canvas Scaler (Script)という項目があるので、そこの設定を以下のようにしましょう。これで、横幅を基準に横1080x縦1920の領域として画面がレンダリングされます。

Unity EditorのGameウィンドウで確認すると、アスペクト比や位置を維持していますね。

次は、Hierarchyに表示されているCanvas > Buttonをクリックすると右側のInspectorに、Buttonに設定されてるコンポーネントの情報が表示されます。
Rect Transformという項目があるので、そこの設定を以下のようにしましょう。これでボタンが中心に位置して大きくなります。

文字もよしなに大きくするとAndroid上でこんな感じになります。

ボタンの実装はこれで良さそうです。
ボタンがクリックしたことを検知
次は、ボタンイベントを取得しましょう。Assets > Create > C# ScriptでC#ファイルをUntiyプロジェクトに作成します。名前は今回はButtonClickとしました。 Start() メソッドはUnityのロジックから呼ばれるものでシーンの1番最初に呼ばれます。Update()メソッドもUnityのロジックから呼ばれるものでシーンの描画の際毎回呼ばれます。このクラスにボタンが押されたら呼ばれるメソッドを実装します。メソッド名は適当に、onClickにして、呼ばれたらログを出すようにしておきます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ButtonClick : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void onClick(){
Debug.Log("On Click");
}
}
この作成したButtonClickクラスをインスタンス化できるように、GameObjectにアタッチしようと思います。
Hierarchyウィンドウで右クリックを押してCreate EmptyをクリックでGameObjectが設置されます。この設置されたGameObjectをクリックすると、右側のInspectorにはTransformだけが表示されていると思います。GameObjectにButtonClickクラスをアタッチするのは簡単で、先ほど作成したC#ScriptをInspectorウィンドウにドラッグアンドドロップするだけです。(Add Componentからもアタッチできます。
GameObjectへのアタッチを終えたら、次はButtonからonClick()呼べるようにします。HierarchyウィンドウにあるButtonのInspectorを開きます。Button (Script)の項目にOn Click()があり、そこは、List is Emptyになってると思います。

On Click()についている+マークを押すと、このようにListに要素が追加されます。

Hierarchyウィンドウにある先ほど作成したGameObjectをOn Click()のListにあるNone (Object)に向かってドラッグアンドドロップすると、次のようになり、ButtonがButtonClickクラスのメソッドにアクセスできる状態になります

No Functionとなっているところをクリックすると、リストがドロップダウンするので、先ほどGameObjectにアタッチしたクラスと、呼びたいメソッドを指定できます。

これでボタンを押すと、ログとOn Click表示されます。実際のUnity Editor上で確認するとこんな感じです。

背景の色を変更
あとは、背景を色で塗りつぶすだけです。Hierarchyウィンドウで右クリックを押してUI > Panelをクリックで、画面を覆う1枚のパネルが設置されます。UnityのHierarchyは上の方が奥側なので、PanelをButtonより上にします。設置したPanelのInspectorを開くと、Image (Script)にColorの項目があるので、これをいじるとパネルの色が変わります。

このパネルの色をonClick()メソッド内で変えることができると良さそうですね。色を変えられるようにButtonClick.csを次のように変更します。このスクリプトのこの状態では、ImageクラスのimgがNullなような気がします。実際、このままではNullなので、Unity Editor上でImageクラスのimgにオブジェクトを代入?アタッチ?します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ButtonClick : MonoBehaviour
{
public Image img;
private bool toggle = false;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void onClick(){
Debug.Log("On Click");
img.color = (toggle)? Color.red : Color.blue;
toggle = !toggle;
}
}
GameObjectのInspectorを開いてみると、ButtonClick (Script)のimgの項目がNone (Image)になっています。None (Image)の右側のターゲットマークをクリックするとImageをアタッチしているGameObjectの一覧が表示されるので、Pnaelを選択します。するとimgにPanelにアタッチされたImageが代入?アタッチ?されます。

これで背景色を変えられるようになったので、アプリは完成です!

(4つも同じアプリを作ってかつまとめると疲れてきますね...
Processing
- クリエイティブコーディングのためのツール
- エンジニアではない人でも簡単に扱える
- ライブラリが様々あって便利
- 言語はJavaで描画をうまくWrapしてくれている
傾向を変えてアAndroidアプリ開発としてはマイナーなProcessingでアプリを作って行きます。
-
Processingをインストールします。公式のダウンロードページからダウンロードしてZIPを解凍するだけです。
-
Processingを起動すると、IDEが立ち上がってすぐにコーディングを開始できます。デフォルトでは
Javaモードなので、PC上でプログラムが動作します。

-
IDE右上の
Java ▼とあるところをクリックするとモードの追加...とあるのでクリックします。すると、ライブラリマネージャーが表示されるので、Android Modeを選択してInstallを押します。インストールが完了するとstatusに緑のチェックマークがつくので、ライブラリマネージャーを閉じます。

-
閉じた後、IDE右上の
Java ▼とあるところをクリックするとAndroidの項目が追加されているので、Androidを押すとAndroidモードになります。 -
またまた、兎にも角にも実行してみます。
Android > Devices >にPCに接続しているデバイスがあることを確認したら、IDE左上の▶マークを押します。すると、ビルドが走りインストールされアプリがRUNします。

ボタンを実装
Processingは描画が専門な感じなので、UIを作るとなるとライブラリが必要になります。 ProcessingではcontrolP5 という、GUI作成するライブラリがあるので、これを使います。
スケッチ > インポートライブラリ > ライブラリを追加... でライブラリマネージャーが開くので、ControlP5を検索し、インストールします。Processingといっても基本はJavaなので、ライブラリのインポートは import controlP5.*; でおしまいです。ボタンをただ置くだけならIDEに次のプログラムを書くだけです。
import controlP5.*;
ControlP5 control;
void setup() {
fullScreen();
control = new ControlP5(this);
control.addButton("onClick")
.setLabel("Red_Button")
.setPosition(50, 40)
.setSize(100, 40)
.setColorActive(color(0, 40)) //押したときの色
.setColorBackground(color(255)) //通常時の色
.setColorForeground(color(255)) //マウスを乗せた時の色
.setColorCaptionLabel(color(0)); //テキストの色
}
void draw() {
}
めちゃくちゃ小さいですが、ボタンを置くことができました。
ボタンがクリックしたことを検知
クリックの検知は簡単で、addButton()の引数と同じ名前のメソッドを作成するだけで、ボタンイベントを拾うことができます。今回は"onClick"としているのでonClick()メソッドを実装します。printlnメソッドを使うとProcessingのIDEのコンソールに文字を表示させられます。
import controlP5.*;
ControlP5 control;
int count = 0;
void setup() {
fullScreen();
control = new ControlP5(this);
control.addButton("onClick")
.setLabel("Red_Button")
.setPosition(50, 40)
.setSize(100, 40)
.setColorActive(color(0, 40)) //押したときの色
.setColorBackground(color(255)) //通常時の色
.setColorForeground(color(255)) //マウスを乗せた時の色
.setColorCaptionLabel(color(0)); //テキストの色
}
void draw() {
}
void onClick(){
println("onClick:" + count);
count++;
}
クリックの検知もできたので、文字もボタンも小さいのを改善します。
まずは文字を改善します。、ツール > フォントの作成...を開いて、好きなフォントを選びます。今回はHelveticaを選びました。サイズを128ぐらいにして、OKを押すとフォントファイルが生成されます。
フォントファイルはloadFontメソッドで読み込んで使います。ボタンのサイズはsetPosition(int,int) setSize(int,int)を使うと改善できそうです。なのでHelloToggleColor.pdeを次のように変更します。
import controlP5.*;
ControlP5 control;
int count = 0;
void setup() {
fullScreen();
PFont p = loadFont("Helvetica-128.vlw");
ControlFont font = new ControlFont(p);
font.setSize(32);
int button_width = (int)(width*0.25);
int button_height = (int)(height*0.08);
control = new ControlP5(this);
control.setFont(font);
control.addButton("onClick")
.setLabel("Button")
.setSize(button_width,button_height)
.setPosition(width/2 - button_width/2, height/2 - button_height/2)
.setColorActive(color(0, 40)) //押したときの色
.setColorBackground(color(255)) //通常時の色
.setColorForeground(color(255)) //マウスを乗せた時の色
.setColorCaptionLabel(color(0)); //テキストの色
}
void draw() {
}
void onClick(){
println("onClick:" + count);
count++;
}
文字のサイズ、ボタンの位置、ボタンのサイズがちょうどよくなりました。
背景の色を変更
Processingで背景を特定の色で塗りつぶすのは簡単です。backgroundメソッドを使うだけなので、プログラムは次のようになります。
import controlP5.*;
ControlP5 control;
int count = 0;
boolean toggle = false;
void setup() {
fullScreen();
background(255, 0, 0);
PFont p = loadFont("Helvetica-128.vlw");
ControlFont font = new ControlFont(p);
font.setSize(32);
int button_width = (int)(width*0.25);
int button_height = (int)(height*0.08);
control = new ControlP5(this);
control.setFont(font);
control.addButton("onClick")
.setLabel("Button")
.setSize(button_width,button_height)
.setPosition(width/2 - button_width/2, height/2 - button_height/2)
.setColorActive(color(0, 40)) //押したときの色
.setColorBackground(color(255)) //通常時の色
.setColorForeground(color(255)) //マウスを乗せた時の色
.setColorCaptionLabel(color(0)); //テキストの色
}
void draw() {
}
void onClick(){
println("onClick:" + count);
count++;
toggle = !toggle;
if(toggle){
background(0, 0,255);
}else{
background(255, 0, 0);
}
}
これでProcessingでも完成しました。
openFrameworks
- クリエイティブコーディングのためのツール
- エンジニアではない人でも簡単に扱える
- アドオンが豊富で便利
- C++で書かれているため速度だせる(?)
同じく、Androidアプリ開発としてはマイナーなopenFrameworksでアプリを作ります。
この記事では v0.11.0 の android 版を使います。
-
openFrameworksをインストールします。これも、公式のダウンロードページからダウンロードしてZIPを解凍するだけです。 今回は、mobileの行にあるAndroid版をダウンロードしてきます。
2.of_v0.11.0_android_release/projectGenerator-{OS} ディレクトリにあるprojectGeneratorを開きます。初めて開くとおそらくopenFrameworksのパスを求められるので先ほどダウンロードして展開したディレクトリを選択します。Project Nameにプロジェクトの名前、Project pathにプロジェクトの保存先を指定して、Generateを押すとopenFrameworksのプロジェクトが生成されます。(念のためPlatformがAndroidになっていることを確認しておきましょう


Android Studio側でTools -> Create Command-line Launcher...の設定を行っているとOpen in IDEでAndroid Studioが開きます。
3.筆者は設定していないので手動でAndroid Studioを開き、 Import Project (Gradle ,Eclipse ADT, etc.) をクリックして、生成されたプロジェクトのディレクトリを選択します。Openを押すと自動でGradle Syncが走ります。(Gradle Syncが走らない場合は、手動でSyncします。

4.Gradle Syncに失敗した場合は、build.gradleとsettings.gradleを修正する必要があります。スクリプトファイルでは、openFrameworksのパスが../../../になっているので正しいパスに直します。
自分の環境では/Users/cha84rakanal/Documents/of_v0.11.0_android_releaseディレクトリにopenFrameworksを配置しているので、そのパスに置き換えます。
def ofRoot(){ return '/Users/cha84rakanal/Documents/of_v0.11.0_android_release/' }
// Load common functions
apply from: ofRoot()+"libs/openFrameworksCompiled/project/android/common-functions.gradle"
buildscript {
apply from: "/Users/cha84rakanal/Documents/of_v0.11.0_android_release/libs/openFrameworksCompiled/project/android/ndk-verify.gradle"
repositories {
jcenter()
}
dependencies {
// Using the gradle-experimental version that supports c++
classpath 'com.android.tools.build:gradle-experimental:0.9.3'
}
}
// openFrameworks-relative root directories (don't touch)
def ofRoot = '/Users/cha84rakanal/Documents/of_v0.11.0_android_release/'
// Load common functions
apply from: ofRoot+"libs/openFrameworksCompiled/project/android/common-functions.gradle"
ERROR: Wrong version of NDK library found. Found version 19.2.5345600, but openFrameworks requires version r15cというエラーが出た場合は、local.propertiesを編集してAndroid NDK r15cのインストールされてるパスを指定します。
5.Gradle Syncが通れば、まずは実行してみます

灰色で背景が塗りつぶされていれば正しいです。
ボタンを実装
openFrameworksもProcessingと同様に、描画が専門な感じなので、UIを作るとなるとアドオンが必要になります。openFrameworksではofxDatGui という、GUI作成するアドオンがあるので、これを使います。 試してみたらofxDatGuiを使ってできなかったので、 Android Studio + NDKで使った方法でボタンを実装していきます。(この方法はずるいなぁと思いながら...
AndroidManifest.xmlをみると、起動するActivityがcc.openframeworks.HelloColorToggle.OFActivityとなっているので、srcJava/OFActivity.javaを見てみます。
<activity
android:name="cc.openframeworks.HelloColorToggle.OFActivity"
android:label="@string/app_name"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
OFActivity.javaにはこれといった実装はないのですが、cc.openframeworks.OFActivityクラスを継承しています。なので、cc.openframeworks.OFActivityにマウスカーソルを合わせて、右クリックしてGo To > Declarationで定義に飛びます。
すると、this.setContentView(view);で、R.layoutのXMLで定義されたViewを読み込んでいることを発見できました。
public void initView(){
String packageName = this.getPackageName();
try {
Log.v("OF","trying to find class: "+packageName+".R$layout");
Class<?> layout = Class.forName(packageName+".R$layout");
View view = this.getLayoutInflater().inflate(layout.getField("main_layout").getInt(null),null);
if(view == null) {
Log.w("OF", "Could not find main_layout.xml.");
throw new Exception();
}
this.setContentView(view);
Class<?> id = Class.forName(packageName+".R$id");
mOFGlSurfaceContainer = (ViewGroup)this.findViewById(id.getField("of_gl_surface_container").getInt(null));
if(mOFGlSurfaceContainer == null) {
Log.w("OF", "Could not find of_gl_surface_container in main_layout.xml. Copy main_layout.xml from latest empty example to fix this warning.");
throw new Exception();
}
} catch (Exception e) {
Log.w("OF", "couldn't create view from layout falling back to GL only",e);
mOFGlSurfaceContainer = new FrameLayout(this);
this.setContentView(mOFGlSurfaceContainer);
}
}
なので、ボタンを配置するだけなら、res/layout/main_layout.xmlで配置するだけでおしまいです。main_layout.xmlを次のように編集するとボタンが置かれます
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/relativeLayout1" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout android:id="@+id/of_gl_surface_container" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<!-- add here other views' layouts -->
</RelativeLayout>
ボタンがクリックしたことを検知
次は、ボタンがクリックしたことを検知します。親クラスでsetContentView()したViewに子クラスでもアクセスできるのでsrcJava/OFActivity.javaでボタンにOnClickListenerを実装します。(普通に親のabstructクラスに実装はするのはよくないし...
サクッとfindViewById()メソッドをつかってsetOnClickListener()メソッドでOnClickListener当てます。これで、ボタンをクリックするとログにonClickと表示されます。
public class OFActivity extends cc.openframeworks.OFActivity{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.e("of","onClick");
}
});
}
今回も描画自体は、C++側で実装されているので、JNIを使ってC++側にボタンがクリックされたことを伝えて行きます。
まずは、C++側にJavaから呼び出せる関数を実装します。src/ofApp.hに#include <jni.h>を加えます。
# pragma once
# include "ofMain.h"
# include "ofxAndroid.h"
# include <jni.h> // <---- 追加
class ofApp : public ofxAndroidApp{
public:
//----省略----//
次に、実際に呼び出す関数をsrc/ofApp.cppに実装します。今回はclickというメソッド名で呼び出せるようにします。命名規則通りの関数名は次のようになります。
# include "ofApp.h"
extern "C"
JNIEXPORT void JNICALL
Java_cc_openframeworks_HelloColorToggle_OFActivity_click(JNIEnv* env,jobject thiz){
ofBackground(255,255,255);
}
//--------------------------------------------------------------
void ofApp::setup(){
}
あんまり良くないTipsですが、 C++でつける関数名がわからない場合は、C++で何も実装せずにJava側でpublic native {戻り値の型} {関数名}(引数...);とメソッド名だけ定義して適当なところで呼び出す形で実行します。アプリがUnsatisfiedLinkErrorをだして、本来呼べたはずの関数名をログに出力するので、それを使います。下の場合だとhoge()というメソッド名で関数を作成したい場合はJava_cc_openframeworks_HelloColorToggle_OFActivity_hogeという関数名でC++側で実装するべきたとわかります。
2019-12-03 12:18:09.617 17648-17648/cc.openframeworks.HelloColorToggle E/AndroidRuntime: FATAL EXCEPTION: main
Process: cc.openframeworks.HelloColorToggle, PID: 17648
java.lang.UnsatisfiedLinkError: No implementation found for void cc.openframeworks.HelloColorToggle.OFActivity.hoge() (tried Java_cc_openframeworks_HelloColorToggle_OFActivity_hoge and Java_cc_openframeworks_HelloColorToggle_OFActivity_hoge__)
at cc.openframeworks.HelloColorToggle.OFActivity.hoge(Native Method)
at cc.openframeworks.HelloColorToggle.OFActivity$1.onClick(OFActivity.java:27)
at android.view.View.performClick(View.java:6294)
at android.view.View$PerformClick.run(View.java:24770)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
OFActivity.javaを次のように編集すると、ボタンをクリックすると背景が白く塗りつぶされるアプリが完成します。
public class OFActivity extends cc.openframeworks.OFActivity{
public native void click();
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
click();
}
});
}
背景の色を変更
ボタンのクリックでもうやってしまいましたが、背景色を変えるのは、ofBackground(int 0-255,int 0-255,int 0-255);ですね。openFrameworksの構造はofApp::setup()はアプリが立ち上がった後の1回のみ呼ばれて、画面描画ごとにofApp::update() ofApp::draw() が呼ばれます。それを踏まえて、ofApp.cppを次のように編集します。
# include "ofApp.h"
static bool toggle;
extern "C"
JNIEXPORT void JNICALL
Java_cc_openframeworks_HelloColorToggle_OFActivity_click(JNIEnv* env,jobject thiz){
toggle = !toggle;
}
//--------------------------------------------------------------
void ofApp::setup(){
toggle = true;
ofBackground(255,0,0);
}
//--------------------------------------------------------------
void ofApp::update(){
}
//--------------------------------------------------------------
void ofApp::draw(){
if(toggle)
ofBackground(255,0,0);
else
ofBackground(0,0,255);
}
ボタンはmain_layout.xmlのボタン要素にandroid:layout_centerInParent="true"を加えるだけで真ん中にきます。

Cordova
- 簡単にクロスプラットフォーム
- HTML/JS/CSSが分かれば、アプリを作れる
- Webの資産を使い回せる
今度は、Nativeから離れて、WebViewを元に作られているCordovaというフレームワークを使ってアプリを作ります。
1.Cordovaをインストールします。npmが入っていることが前提です。ターミナルに次のコマンドを打ち込むだけでインストールは終わりです。
$npm install -g cordova
2.アプリのプロジェクトを作成します。事前にアプリのプロジェクトを生成するディレクトリへ移動しておきます。
$cordova create HelloToggleColor
プロジェクトディレクトリを見てみると、index.html や index.js が見受けられるので、どうやらこれらを編集して開発をすすめていけば良さそうな気がします。
HelloToggleColor
├── config.xml
├── hooks
│ └── README.md
├── package.json
├── platforms
├── plugins
└── www
├── css
│ └── index.css
├── img
│ └── logo.png
├── index.html
└── js
└── index.js
3.プロジェクトディレクトリに移動して、Platformを追加します。今回は、Androidアプリなのでandroidを追加します。
$cd HelloToggleColor
$cordova platform add android
4.アプリを起動します。実機をつないでいれば自動でインストールされた立ち上がります。
$cordova run android
え、やば、簡単すぎんか...?
$adb shell dumpsys activity topを使うとViewの構成とかが見れます。なので、Cordovaアプリがどうなっているかというと、SystemWebView で構成されていることがわかります。
TASK io.cordova.hellocordova id=140 userId=0
ACTIVITY io.cordova.hellocordova/.MainActivity 17398e4 pid=24311
View Hierarchy:
DecorView@8e127c8[MainActivity]
android.widget.LinearLayout{ead1061 V.E...... ........ 0,0-1080,1794}
android.view.ViewStub{6b3b786 G.E...... ......I. 0,0-0,0 #1020187 android:id/action_mode_bar_stub}
android.widget.FrameLayout{4142847 V.E...... ........ 0,63-1080,1794 #1020002 android:id/content}
org.apache.cordova.engine.SystemWebView{ec4f874 VFEDH.C.. .F...... 0,0-1080,1731 #64}
android.view.View{b49519d V.ED..... ........ 0,1794-1080,1920 #1020030 android:id/navigationBarBackground}
android.view.View{183c612 V.ED..... ........ 0,0-1080,63 #102002f android:id/statusBarBackground}
ここからの気持ちはAndroidアプリ開発ではなくモバイルWeb開発なのか...と思いながら目的のアプリを作っていきます。
ボタンを実装
HTMLなら <button>タグを追加するだけでbuttonを置けます...
<body>
<button type=button>Button</button>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/index.js"></script>
</body>
Androidなのに味気が無いので、マテリアルデザインっぽいボタンしていきます。
今はサポートされて無いですが、ボタンだけなら扱いやすいので、Material Design Liteを導入します。プロジェクトのディレクトリに移動して次のコマンドを実行してローカルに落としてきます。
$npm install material-design-lite --save
CordovaのHTMLからは、基本的には、path/to/project/wwwのフォルダしかアクセスできないようなので、./node_modules/から ./wwwへcssとjsファイルをコピーします。
cp ./node_modules/material-design-lite/material.min.css ./www/css/
cp ./node_modules/material-design-lite/material.min.js ./www/js/
あとは、ヘッダーに次のコードを追加して、HTMLでの読み込みは完了です。
<link rel="stylesheet" href="./css/material.min.css">
<script src="./js/material.min.js"></script>
ボタンを中央に置きたいので index.css に次のコードを追加して、index.htmlのButton要素を囲います。
.wrap2 {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
<div class="wrap2">
<button class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect">
Button
</button>
</div>
NativeのUIとほとんど変わらないように見えます
ボタンがクリックしたことを検知
これも楽ですね。ButtonタグにonClickプロパティをつけるか、JavascriptでaddEventListenerを使うかです。
今回はJavascriptを書きます。js/index.jsを開いてコードをサクッと実装します。ここでのconsole.log()は、Google ChromeのInspectorにログを出力できます。GoogleChromeのアドレスバーにchrome://inspect/と入力してページを開き、端末のinspectを押すと、実行中の画面とともに、consoleが表示されます。
var app = {
// Application Constructor
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
document.getElementById('button1').addEventListener('click',()=>{
console.log('click');
});
},
背景の色を変更
あとは背景の色を変えるだけです。CSSのbackgtoundプロパティをいじっていきます。js/index.jsを開いてコードを加えます。
var app = {
toggle: false,
// Application Constructor
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
document.getElementById('back').style.background = 'red';
document.getElementById('button1').addEventListener('click',()=>{
document.getElementById('back').style.background = (this.toggle)? 'red' : 'blue';
this.toggle = !this.toggle;
console.log('click');
});
},
ボタンに設定されているアルファ値が低いので後ろの色が反映されてしまいましたがCordovaでも同じアプリができました。
React Native
Getting Startedのページに行くと、React Nativeの開発ツールとしてExpo CLIを使うのとReact Native CLIを使うのとがある。
まずは、Expo CLI から試してみることにする。
1.まず、Expo CLIをインストール。
$npm install -g expo-cli
2.プロジェクトを作るディレクトリに移動して、プロジェクトを生成
$expo init HelloToggleColor
Node.jsのバージョンはサポートしているものに上げる必要がある。
ERROR: Node.js version 10.8.0 is no longer supported.
expo-cli supports following Node.js versions:
* >=8.9.0 <9.0.0 (Maintenance LTS)
* >=10.13.0 <11.0.0 (Active LTS)
* >=12.0.0 (Current Release)
3.どのテンプレートで作成するか聞かれるので、blankを選びます。
? Choose a template: (Use arrow keys)
----- Managed workflow -----
❯ blank a minimal app as clean as an empty canvas
blank (TypeScript) same as blank but with TypeScript configuration
tabs several example screens and tabs using react-navigation
----- Bare workflow -----
minimal bare and minimal, just the essentials to get you started
minimal (TypeScript) same as minimal but with TypeScript configuration
4.プロジェクトが生成されたら、まずは端末で実行します。プロジェクトのディレクトリに移動して、npm start します。
cd HelloToggleColor
npm start
すると、サーバーが立ち上がり、ブラウザに開発ツール、ターミナルにQRコードが表示されます。

5.実行する端末で Expo というアプリをインストールしておきます。

6.インストールされたExpoアプリでQRコードをScanすると、JavaScriptをバンドルして、アプリが表示されます。

ターミナルでは次のコマンドが使えるので、a を押すとターミナルからアプリを起動できます。
› Press a to run on Android device/emulator, or i to run on iOS simulator, or w to run on web.
› Press c to show info on connecting new devices.
› Press d to open DevTools in the default web browser.
› Press shift-d to disable automatically opening DevTools at startup.
› Press e to send an app link with email.
› Press p to toggle production mode. (current mode: development)
› Press r to restart bundler, or shift-r to restart and clear cache.
› Press s to sign in.
ボタンを実装
それでは、ボタンを実装していきます。アプリのメインが画面を作成しているところは App.jsなので、これを編集していきます。
HTMLのノリで <button> ダグを置いてみます。
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<button><Text>Button</Text></button>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
よくわからないときは公式ドキュメントを見てみます。公式ドキュメントのボタンの項目のサンプルコードを参考に書き直します。
import React from 'react';
import { StyleSheet, Text, Button,View } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<Button
onPress={this.onPressLearnMore}
title="Learn More"
color="#858585"
accessibilityLabel="Learn more about this purple button"
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
なんとかボタンが表示されました。
ボタンがクリックしたことを検知
ボタンが押されたらonPressにセットしたメソッドが呼ばれるのでメソッドを実装します。
import React from 'react';
import { StyleSheet, Text, Button, View, Alert} from 'react-native';
export default function App() {
onPressLearnMore = ()=>{
Alert.alert('pressed button')
};
return (
<View style={styles.container}>
<Button
onPress={this.onPressLearnMore}
title="Learn More"
color="#858585"
accessibilityLabel="Learn more about this purple button"
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
ボタンを押したらダイアログが表示されるようにしました。
背景の色を変更
背景の色を変えます。画面いっぱいに構成されているViewコンポーネントのスタイルを変更するのが良さそうです。まずは、styleに背景が赤になるスタイルと青になるスタイルを加えます。
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
red: {
flex: 1,
backgroundColor: '#f00',
alignItems: 'center',
justifyContent: 'center',
},
blue: {
flex: 1,
backgroundColor: '#00f',
alignItems: 'center',
justifyContent: 'center',
},
});
ボタンが押されたら、setStateを呼び出して、Viewに割り当てるスタイルを変えます。さっきは、export default fuctionでしたが、export default classに変えておきます。
export default class App extends React.Component{
constructor(props) {
super(props);
this.state = {
styleVal : styles.container,
toggle : true
}
}
onPressLearnMore = () => {
this.setState(
{
styleVal : (this.state.toggle)?styles.red : styles.blue,
toggle : !this.state.toggle
}
);
}
render = () => {
return (
<View style={this.state.styleVal}>
<Button
onPress={this.onPressLearnMore}
title="Learn More"
color="#858585"
accessibilityLabel="Learn more about this purple button"
/>
</View>
);
}
};
これでなんとかReact Nativeでもできました!
Visual Studio
まずはインストールから初めていきます。(Windowsの方はすみません
1.MSのVisual Studioのページにいき、インストーラーをダウンロードします。今回は、Visual Studio for Macをダウンロードしてきます

2.ダウンロードしたdmgを開いてインストーラーを起動します。インストールするコンポーネントのAndroidにチェックがついていることを確認してインストールを押します。

3.Visual Studioを開き、+新規でプロジェクトを新しくプロジェクトを作成します

Visual Studioで作成できるAndroidアプリはXamarin.FormsとXamarin.Androidがあるので、まずはXamarin.Formsでアプリを作っていきます。
Xamarin.Forms
1.マルチプラットフォームで、空白フォームのアプリを選択します。

2.必要な情報を入力します。

3.プロジェクトの保存先などを指定して作成します。

とりあえず実機で実行してみます。この部分で実行するOSと端末を設定します。

こんな感じで Welcome to Xamarin.Forms!と画面中央に設置されます。

ボタンを実装
まずは、ボタンを設置していきます。最初の画面はMainPage.xmalで構成されているので、編集していきます。
Android Studioで読み書きするactivity_main.xmlに似ていますね。要素だったところを要素に変えるだけです。IDEの右側にコンポーネントのリストがあるので実際ドラッグアンドドロップで要素を置けるの楽ですね。
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="HelloToggleColor.MainPage">
<StackLayout>
<!-- Place new controls here -->
<Button Text="Button" HorizontalOptions="Center" VerticalOptions="CenterAndExpand"/>
</StackLayout>
</ContentPage>
ボタンがクリックしたことを検知
次はボタンクリックの検知です。MainPage.xmalに対応して、MainPage.xmal.csがあるので、おそらくイベント処理的なものはここに書いて行けば良さそうです。まずはボタンをクリックしたら呼ばれる関数を実装します。C#でのログ出力はSystem.Console.WriteLineを使います。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace HelloToggleColor
{
// Learn more about making custom code visible in the Xamarin.Forms previewer
// by visiting https://aka.ms/xamarinforms-previewer
[DesignTimeVisible(false)]
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
void OnButtonClicked(object sender, EventArgs args)
{
Console.WriteLine("DEBUG - Button Clicked!");
}
}
}
ボタンにはどの関数を呼び出せばいいかをClickedプロパティにセットしておきます。
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="HelloToggleColor.MainPage">
<StackLayout>
<!-- Place new controls here -->
<Button Text="Button"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnButtonClicked" />
</StackLayout>
</ContentPage>
これでボタンを押すとログにDEBUG - Button Clicked!とでるアプリができました。

背景の色を変更
MainPage.xmal.csでロジックを書いて、MainPage.xmalでViewを書くことがわかったのであとは簡単です。
MainPage.xmal.csから参照できるように、MainPage.xmalの要素にNameプロパティを設定します。
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="HelloToggleColor.MainPage">
<StackLayout x:Name="layout">
<!-- Place new controls here -->
<Button Text="Button"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnButtonClicked" />
</StackLayout>
</ContentPage>
Nameプロパティにセットした名前で直接アクセスできるので、BackgroundColorプロパティに色を代入するだけでおしまい。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace HelloToggleColor
{
// Learn more about making custom code visible in the Xamarin.Forms previewer
// by visiting https://aka.ms/xamarinforms-previewer
[DesignTimeVisible(false)]
public partial class MainPage : ContentPage
{
private bool toggle = true;
public MainPage()
{
InitializeComponent();
}
void OnButtonClicked(object sender, EventArgs args)
{
Console.WriteLine("DEBUG - Button Clicked!");
layout.BackgroundColor = toggle ? Color.Red : Color.Blue;
toggle = !toggle;
}
}
}
はぇ〜、Android Studio + C#みたいな感じで開発しやすい。
Xamarin.Android
Xamarin.Androidも試していきます。
1.Visual Studioを開いて、新規で空のネイティブアプリ(iOS、Android)を選択します。

2.必要な情報を入力します。

3.これでプロジェクトが完成しました。

テンプレートなのに既にボタンもボタンイベントへの反応も実装されている!?
ボタンを実装
既にボタンは実装されますが、どこでボタンが実装されているのかは確認します。この画面のレイアウトはResources/layout/Main.axmlに定義されています。中ををみると、普通にAndroidのレイアウトファイルになっているいます。なので、ボタンが中央にある感じに直しちゃいます。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button android:id="@+id/myButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/hello" />
</RelativeLayout>
ボタンがクリックしたことを検知
ボタンがクリックしたことを受け取るロジックは、MainActivity.csに書かれています。Javaのメソッド名のままC#に持ってきた感じがすごいします。interfaceの代わりにdelegateが使われてるのが特徴的です。
using Android.App;
using Android.Widget;
using Android.OS;
namespace HelloToggleColor.Droid
{
[Activity(Label = "HelloToggleColor", MainLauncher = true, Icon = "@mipmap/icon")]
public class MainActivity : Activity
{
int count = 1;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.myButton);
button.Click += delegate {
Android.Util.Log.Info("Xamarine","onClick");
};
}
}
}
背景の色を変更
delegateのあたりをいじって従来のAndroid開発のノリでサクッと書きます。今回はボタンの親Viewが背景のRelativeLayoutだとわかっているので、親を取得してキャストして背景色を変えます。
using Android.App;
using Android.Widget;
using Android.OS;
namespace HelloToggleColor.Droid
{
[Activity(Label = "HelloToggleColor", MainLauncher = true, Icon = "@mipmap/icon")]
public class MainActivity : Activity
{
private bool toggle = true;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.myButton);
button.Click += delegate {
Android.Util.Log.Info("Xamarine","onClick");
((RelativeLayout)button.Parent).SetBackgroundColor((toggle)?Android.Graphics.Color.Red : Android.Graphics.Color.Blue);
toggle = !toggle;
};
}
}
}
Android Studio + C#な感じで開発しやすかった。
最後に
Web系の知識と、Android Studioでの開発がわかってると、色んなフレームワークをサクッと使っていける感じはありました。
今回試したフレームワークでも、普段より楽な点や面倒な点もあるので、やっぱり作るものに応じてという感じがします。
フレームワークによってはHello Worldアプリの実行まで10分もかからないものもあるので、Eclipseを使って開発していた頃とは違うし、めちゃくちゃ敷居は低くなったと思います。なので、Androidアプリを作りたいなぁとか思ってる人は、どれかフレームワークでも選んでサクッと作り始めるのがいいです。
もうちょっとフレームワークの利点・欠点の説明とか、フレームワークの仕組みとかにも触れて話していきたいので、随時更新していくのでよろしくお願いします。













































