Android OS/開発環境が進歩する一方で、私の家には古くて一般的には使えないAndroid 1.6の端末が転がっています。しかし古すぎる為か、最新の開発環境ではすんなりとビルドすることが出来ませんでした。
ここでは、Android Studio 2.x環境でAndroid 1.6向けのアプリケーションをビルドするための方法を紹介したいと思います。
何故に今更Android1.6なのか
ことの発端は、今更ながら、家に転がっているSharp IS01を携帯データロガーとして活用する方法を考えたことです。
IS01はOSがAndroid 1.6ですが、小さいながらH/Wキーボードとトラックボールがついていて、GPSとGセンサーに時計、通信手段としてWifiとBluetoothを搭載しています。当然ながらバッテリー(と充電回路)も搭載しているので、バッテリーが生きていれば瞬停対策もばっちりです。こいつを使えばいい感じのが作れるのでは、と考えました。
もちろん、巷にはIS01からすれば段違いに性能が良く画面も大きい7inchタブレットが販売されています(激安の中華タブレットだと5,000円とか)。これからすればIS01など塵芥に等しく、わざわざ古いAndroid端末を購入するメリットは無いでしょう。
ただ、いくら古い端末とはいえ、電子工作でよくお世話になるArduinoやPICマイコンと比較すれば非常に高性能です。CPUやメモリのリソースはもちろん、GPS等のセンサー類はてんこ盛りですし、WifiにBluetooth、(生きていれば)バッテリーと専用の充電回路、当たり前ながらディスプレイ+タッチセンサーまで載っているのです。売っても二束三文(そもそも買い手がいる?)、これを活用してやらない手はありません。
次に対応OSのバージョンです。
IS01などいくつかの恵まれた端末には、有志の方が作られたAndroid 2.2(Froyo)やAndroid 4.x環境のカスタムOSが存在しています。OSのバージョンが上がれば使えるAPIも増えるので、アプリケーションはより作りやすくなります。ただ、残念ながらカスタムOSでは搭載されている全てのデバイスに対応していないケースもあり、例えばIS01のカスタムOSを使用するとBluetoothが使えません(そこまで対応していない)。
それに、わざわざはるか昔の端末をデータロガーとして使うためだけにOSを書き換えるという手間をかけるのもちょっと考え物です。
ならばいっそのことAndroid 1.6環境で動作するデータロガーアプリケーションを作ってみよう、となりました。これだけ古い端末でも動作するようにしておけば、私のように自宅で埃をかぶっている端末を活用してやることが出来ます。
開発環境を準備する
Android Studioをインストール
現時点でのAndroidオフィシャルの開発環境はAndroid Stduio 2.1.3です。Android1.6の対応は終了しており、何も考えずにウィザードを使って作ったアプリをビルドしても動作させることが出来ません。少し手間が必要です。
まずはオフィシャルサイトからAndroid Studioをダウンロードしてインストールしてください。
PC環境にSun Javaが未インストールの場合は、Android Studioより先にJavaのダウンロードとインストールが必要です。JavaのVersion 8以上にしておいたほうが良いようです(Android Studioのインストール画面でJava version 7のリンクが表示されることがありましたが、version7だとビルドするときにエラーが発生しました)。
- Oracle Java
(https://java.com/ja/download/) - Android Studio
(https://developer.android.com/studio/index.html?hl=ja)
SDK,Support libraryの追加
次に、Android1.6環境向けにビルドするために必要なSDKとSuport Libraryを入手します。Android Studioを起動して、
- Android Stduioメニューバー > Tools > Android > SDK Managerを選択
- 表示された画面の右下にある"Launch Standalone SDK Manager"を選択
- "Android SDK Manager"が立ち上がるので、画面の左下にある"Obsolete"チェックボックスを選択(これをしないと1.6のものが表示されない)
- Package一覧から以下のものを選択
- Android 5.1.1(API 22)
- Android 1.6(API 4)
- Extras > Android Support Repository
- Extras > Android Support Library (Obsolete)
- "Install packages..."をクリック
これで必要なSDKとライブラリがインストールされます。
Instant Run機能を無効にする
IS01の実機環境でデバッグを行う場合、"Instant Run"機能を無効にする必要がありました。この機能はデバッグ時にアプリケーションを端末に転送する時間を大幅に短縮するもので、Android 4.4(API 20)以降のOSが対応しています。
オフィシャルサイトの説明を読む限りでは、未対応の環境でデバッグする際には自動的に無効になるように思えるのですが、私が試したところIS01環境で実行するとエラーが発生してアプリケーションが起動しませんでした。なので、明示的にInstant Runを無効にしてやります。
- Android Studioメニューバー > File > Settings...を選択
- 表示された"Settings"画面左から Build,Execution,Deployment > Instant Runを選択
- 画面右の"Enable Instant Run to hot swap code/resource changes on deploy (default enabled)"のチェックを外す
実機ではなくAndroid 4.4以降のエミュレータ環境でデバッグを行う際は、上記のInstant Runを有効にしておいた方がいいかもしれません。デプロイの時間が大幅に短縮されるようです。
空のプロジェクトを作る
Android Studioは画面のひな形となるファイルを作成してくれます。通常はそのままビルドして実行環境に転送してやれば動くはずですが、Android1.6ともなるとビルドエラーが発生してしまいます。そこで、画面構成は自分でつくってやることにします。
- Android Studioメニュー > File > New > New Project...
- Minimum SDKは"API 4: Android 1.6 (Donut)"を選択します。
- Acitivityはここでは作成しません。"Add No Activity"を選択します。
Support Libraryのバージョンを変更する
これでプロジェクトは作成出来ましたが、おそらくビルドには失敗しているはずです。古い端末(OS)でも新しい機能が利用できるようにSupport Libraryが自動的に設定されますが、これのバージョンに問題があります。
例えば、現時点での最新版(Revision 24.2.0)を使用すると、実行時に以下のようなエラーを吐いて落ちます。
------------
09-06 09:53:58.367 32224-32224/com.suke_blog.supportlibfragmenttest2 E/dalvikvm: Could not find method android.support.v4.app.BaseFragmentActivityJB.onBackPressed, referenced from method android.support.v4.app.FragmentActivity.onBackPressed
09-06 09:53:58.367 32224-32224/com.suke_blog.supportlibfragmenttest2 W/dalvikvm: VFY: unable to resolve virtual method 2056: Landroid/support/v4/app/BaseFragmentActivityJB;.onBackPressed ()V
09-06 09:53:58.367 32224-32224/com.suke_blog.supportlibfragmenttest2 W/dalvikvm: VFY: rejecting opcode 0x6f at 0x000c
09-06 09:53:58.367 32224-32224/com.suke_blog.supportlibfragmenttest2 W/dalvikvm: VFY: rejected Landroid/support/v4/app/FragmentActivity;.onBackPressed ()V
09-06 09:53:58.367 32224-32224/com.suke_blog.supportlibfragmenttest2 W/dalvikvm: Verifier rejected class Landroid/support/v4/app/FragmentActivity;
09-06 09:53:58.367 32224-32224/com.suke_blog.supportlibfragmenttest2 W/dalvikvm: Class init failed in newInstance call (Lcom/suke_blog/supportlibfragmenttest2/MainActivity;)
09-06 09:53:58.367 32224-32224/com.suke_blog.supportlibfragmenttest2 W/dalvikvm: threadid=3: thread exiting with uncaught exception (group=0x2aac5a18)
09-06 09:53:58.367 32224-32224/com.suke_blog.supportlibfragmenttest2 E/AndroidRuntime: Uncaught handler: thread main exiting due to uncaught exception
09-06 09:53:58.387 32224-32224/com.suke_blog.supportlibfragmenttest2 E/AndroidRuntime: java.lang.VerifyError: android.support.v4.app.FragmentActivity
-----------
Support Libraryのヒストリーを見てみると、以下のような注意書きがありました。どうやらAndroid 2.2以下はサポートが打ち切られ、Revision 24.2.0以降のSupport LibraryはAndroid1.6では動かないようです。
Note: Release 24.2.0 removes support for Android 2.2 (API level 8) and lower. Classes and methods that exist only to serve those system versions are now marked as deprecated and should no longer be used. These deprecated classes and methods may be removed in a future release.
では、どのバージョンであれば動くのかというと、私が試したところ Revision 22.2.1であればIS01でも動作しました。それ以降のバージョンでは起動時にエラーが発生して動作しません。
早速、プロジェクトに設定してみます。
- Android Studioメニュー > File > Project Structure...
- 画面左の"app"を選択し、"Dependencies"タブを選択
- 画面右の"+" > "Library Dependencies"を選択して以下の二つを追加
- com.android.support:support-v4:22.2.1
- com.android.support:appcompat-v7:22.2.1
Support Libraryの末尾":"以下はバージョンです。単純にリストからライブラリを選択すると最新バージョンのものが入力されるので、手動で"22.2.1"に書き換える必要があります。
また、最初からappcompat-v7等のバージョン違いが追加されている場合、それは削除してください。
また、"Properties"タブと"Flavors"タブにSDKのバージョン設定があります。それぞれ、以下のように設定しました。
(使用するSDKを"Android 7.0"にしてもビルド出来ましたが、一応ライブラリとあわせておきました)
- Properties > Compile Sdk Version : API22 Android5.1(Lolipop) <- Support Libraryのバージョンと合わせる
- Properties > Build Tools Version : 24.0.2 <- 現時点で最新のもの
- Flavors > Min Sdk Version : API4 Android 1.6 (Donut)
- Flavors > Target Sdk Version : API22 Android5.1(Lolipop) <- Support Libraryのバージョンと合わせる
Support LibraryをAPI-9以下のプロジェクトでビルドできるようにする
追加したSupport LibraryはAPI-9以上を対象にビルドされているため、Android 1.6(API-4)ではビルドエラーが発生します。
-------
Error:Execution failed for task ':app:processDebugManifest'.
> Manifest merger failed : uses-sdk:minSdkVersion 4 cannot be smaller than version 9 declared in library [com.android.support:appcompat-v7:24.2.0] F:\win_googledrive_sync\Android_Project\MyApplication\app\build\intermediates\exploded-aar\com.android.support\appcompat-v7\24.2.0\AndroidManifest.xml
Suggestion: use tools:overrideLibrary="android.support.v7.appcompat" to force usage
-------
そこでAndroidManifest.xmlを修正してビルドエラーが発生しないようにします。
以下の2行を追加します。
- xmlns:tools="http://schemas.android.com/tools"
- <uses-sdk tools:overrideLibrary="android.support.v4, android.support.compat, android.support.coreutils, android.support.mediacompat, android.support.coreui, android.support.fragment, android.support.v7.appcompat, android.support.graphics.drawable, android.support.v4.preferencefragment"/>
[修正前]
[XML]
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.suke_blog.myapplication">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
</application>
</manifest>
[/XML]
[修正後]
[XML]
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.suke_blog.myapplication">
<uses-sdk tools:overrideLibrary="android.support.v4, android.support.compat, android.support.coreutils, android.support.mediacompat, android.support.coreui, android.support.fragment, android.support.v7.appcompat, android.support.graphics.drawable, android.support.v4.preferencefragment"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
</application>
</manifest>
[/XML]
サンプル画面を作成する
ここまでで、ひとまずビルドは通るようになったはずです。AndroidStudioでビルドして"BUILD SUCCESSFUL"となっていることを確認してください。
まだアプリケーションとしては画面も処理も何も無い状態です。試しに画面を作って実機で動作するか確認してみましょう。
(サンプルコードはDevelopers.IO様の記事を参考にさせて頂きました)
以下のclassを新規作成します。
(追加先は"app/java/(package名)/")
- MainActivity
- MainFragment
また、以下のレイアウトファイルを新規作成します。(追加先は"app/res/layout/"、layoutフォルダは初期状態では存在しないので作成する)
- activity_main.xml
- fragment_main.xml
追加した画面を登録して起動時に表示されるようにするために、以下のファイルを修正します。
- AndroidManifest.xml
全て終えると、プロジェクトツリーは以下のようになります。
MainActivity
[JAVA]
package com.suke_blog.myapplication;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.Chronometer;
public class MainActivity extends FragmentActivity implements View.OnClickListener {
Chronometer chronometer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
chronometer=(Chronometer)findViewById(R.id.chronometer);
chronometer.setOnClickListener(this);
}
@Override
protected void onStart() {
super.onStart();
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.chronometer:
chronometer.start();
break;
default:
break;
}
}
}
[/JAVA]
MainFragment
[JAVA]
package com.suke_blog.myapplication;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MainFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main, container, false);
}
}
[/JAVA]
activity_main.xml
[XML]
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.suke_blog.myapplication.MainFragment">
</fragment>
[/XML]
fragment_main.xml
[XML]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:gravity="center"
android:background="#eeeeee"
android:weightSum="1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:text="Hello, SupportFragment!"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
/>
<Chronometer
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/chronometer"
android:layout_gravity="center_horizontal" />
<AnalogClock
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/analogClock"
android:layout_gravity="center_horizontal" />
<DigitalClock
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/digitalClock"
android:layout_gravity="center_horizontal" />
</LinearLayout>
[/XML]
AndroidManifest.xml
内容に上記のactivityを追加しています。
[XML]
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.suke_blog.myapplication">
<uses-sdk tools:overrideLibrary="android.support.v4, android.support.compat, android.support.coreutils, android.support.mediacompat, android.support.coreui, android.support.fragment, android.support.v7.appcompat, android.support.graphics.drawable, android.support.v4.preferencefragment"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
[/XML]
サンプルを動作させる
上記ファイルを追加/修正してビルドが通ったら、早速端末に転送して実行してみます。
あらかじめ使用する端末(ここではIS01)のADBドライバをインストールして、接続できるようにしておいてください。
- Tools > Android > Enable ADB Integrationにチェックを入れる
- Run > Run 'app'で転送先の端末を選択して"OK"ボタンをクリックする
正常に起動すれば、以下のように表示されるはずです。
参考
- Android Studio - Instant Run について
(https://developer.android.com/studio/run/index.html#instant-run) - Android Developpers - Support Library Revision History
(https://developer.android.com/topic/libraries/support-library/revisions.html) - Developers.IO - Android Tips #28 Android 1.6 から Fragment を使う
(http://dev.classmethod.jp/smartphone/android/android-tips-28-support-fragment/) - なるようになるかも - Androidのサポートパッケージについて
(http://quesera2.hatenablog.jp/entry/2015/01/04/001328) - stack overflow - How do I use tools:overrideLibrary in a build.gradle file?
(http://stackoverflow.com/questions/27095077/how-do-i-use-toolsoverridelibrary-in-a-build-gradle-file) - Gihyo.jp - Android Studio最速入門~効率的にコーディングするための使い方
(http://gihyo.jp/dev/serial/01/android_studio?start=40) - 株式会社 阿形 - Androidで使う「wrap_content」「fill_parent」「match_parent」の違いとは
(http://www.agyou.com/technical/422.html) - 今さら聞けない Activity と Fragment の使い分け
(http://qiita.com/KeithYokoma/items/c41b22bda8c8d924d8cd)
ビルドの最中に
Error:(14, 25) エラー: パッケージRは存在しません
となります。原因はよく分かりませんでした。解決策をご存知でしたら教えていただけると嬉しいです。
私も同じようなことがおきました。
Clean Projectしてからビルドしなおすと上手くいくようです。
(あと、AndroidManifest.xmlをのせるの忘れていたので記事に追加しました)
ご返信有り難うございます。アドバイスによって幾つかのエラーが解決できました。ですが次のようなエラーメッセージがやはり消えません。build.gradle (Module: app)の項目が原因のような気がするのですが、このファイルも見せていただけないでしょうか?宜しくお願い致します。
:app:compileDebugJavaWithJack
Error:MainActivity.java:14: R cannot be resolved to a variable
Error:MainActivity.java:28: R cannot be resolved to a variable
むむ。駄目でしたか。
build.gradle (Module: app)の中身は以下のようになっています。
-----
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "com.suke_blog.myapplication"
minSdkVersion 4
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:support-v4:22.2.1'
compile 'com.android.support:appcompat-v7:22.2.1'
}
------
ご返信有り難うございました。よくブログの記事と自信のソースコードを比較した結果、
MainActivityの項目の
package com.suke_blog.myapplication;
が
package suke_blog.myapplication;
となっておりました。
どうりでコンパイラ側がRを探せないはずです。無事にブログの記事の通りIS01で動かすことが出来ました。この度は貴重な記事の執筆ありがとうございました。
動作しましたか!
お役に立てたようでなによりです。まだまだIS01が活躍するようお祈り致します(笑