2013年8月11日日曜日

ListAdapterのgetViewが呼び出される階層を調べてみた

ListViewを継承して独自のカスタムViewを作ろうとしてた時に必要になったので、 ListAdapterのgetViewが呼び出される階層を調べてみた。
android.widget.ListAdapter#getView
↑
android.widget.AbsListView#obtainView
↑
android.widget.ListView#makeAndAddView
↑
android.widget.ListView#fillDown
↑
android.widget.ListView#fillGap
↑
android.widget.AbsListView#trackMotionScroll
↑
android.widget.AbsListView#scrollIfNeeded
↑
android.widget.AbsListView#onTouchEvent
まだ続いてるけどここまでわかればOKでしょ。 ちなみにこれ4.2.2の挙動ね。

2013年6月8日土曜日

githubをMavenリポジトリとしてAndroidライブラリプロジェクト(aar)をデプロイして使用する

序章

Android StudioとGradleのビルドシステム(Plugin)が正式にリリースされ、個人的に気になっていたAndroidライブラリプロジェクトの扱いについて調べてみた。新しいGradleのビルドシステムではライブラリプロジェクトはaar(Android archive)という1つのアーカイブで配布することが可能になった。aarファイルは拡張子によって判別され、フォーマットはzip形式である。(aarファイルについての詳細はまた今度。)従来はライブラリプロジェクトを使用するためにプロジェクト一式が必要だったけど、1つのアーカイブを参照するだけで使用出来るようになるので再利用しやすくなったってこと。

※ちなみにこれまでもandroid-maven-pluginというサードパーティ製のプラグインを使用することで解決されてきたのだけど、個人的には正式にサポートされたというのが大きい。

現時点ではビルドシステムのソースコードを見る限り、aarを参照する方法は"External module dependencies"タイプしかサポートされていない。これはどこかのリポジトリに配置されたモジュールを参照するということ。Gradleでは様々なリポジトリ形式に対応しているので、それらの形式(MavenとかIvyとか)でaarをデプロイする必要がある。

注意したいのはただ単にローカルファイルシステム上に配置されたaarを参照出来ないという点である。以下はNGパターン。

dependencies {
    compile files('path/to/some/a.aar', 'path/to/some/b.aar')
    compile fileTree(dir: 'path/to/some', include: '*.aar')
}

GradleでもMavenリポジトリ形式が一般的っぽいのでとりあえずaarをMavenリポジトリ形式でgithubにアップロードして使用出来るか試してみた。結果何事もなく出来たので手順を公開しておく。

環境

  • Android Studio 0.1.1
  • Mac OS X 10.8.3

デプロイ編

まずはAndroid Studioを使用して新規プロジェクトを作成する。こんな感じ。Eclipseユーザーにはわかりづらいかもしれないけど、Android Studioで新規プロジェクトを作成する場合はプロジェクト=アプリではなく、モジュール=アプリとなる。つまり、1つのプロジェクト内にライブラリモジュールや本体アプリモジュール、テストアプリモジュールを配置していくことになる。慣れればこっちのがわかりやいかもね。ちなみにEclipseでbuild.gradleファイルをエクスポートしてAndroid Studioでインポートする場合は上記の通りではない。

ナビ通り進めていくと以下のようなbuild.gradleを含んだプロジェクトが作成される。

現時点でのAndroid Studioは「Mark this project as a library」にチェックを入れてもライブラリプロジェクトとして扱ってくれないらしい。。なので手動で修正。(ソースコードを見る限りそのうち直ると思う。)

apply plugin: 'android'

の箇所を以下に変更。

apply plugin: 'android-library'

試しにaarが作成されるか、ターミナルを起動してビルドしてみる。aarはデバッグ版はassembleDebug、リリース版はassembleReleaseのGradleタスクで作成される。プロジェクト配下で以下のコマンドを実行。

$ cd <project_home>
$ ./gradlew assembleRelease

以下ファイルが生成されていればOK。

$ find . -name '*.aar'
./library/build/libs/library.aar

続いて、Mavenプラグインを使用してMavenリポジトリ形式でデプロイするためlibrary/build.gradleに追記する。Mavenプラグインについてはここを参照。

// プロジェクトルート配下のrepositoryディレクトリにデプロイする
def deployTo = new File(rootDir, "repository")

// Mavenプラグインの利用を宣言
apply plugin: 'maven'

uploadArchives {
    repositories {
        mavenDeployer {
            repository url: "file://${repos.absolutePath}" // デプロイ先
            pom.version = '0.0.1' // ライブラリバージョン
            pom.groupId = 'com.u1aryz' // グループ名
            pom.artifactId = 'sample-lib' // アーティファクト名
        }
    }
}

ターミナルに移ってプロジェクト配下で以下のコマンドを実行。

$ ./gradlew uploadArchives

プロジェクト配下のrepositoryディレクトリに以下のようにファイル群が出来ていれば成功。

$ ls -laR repository
total 0
drwxr-xr-x   3 u1aryz  staff  102  6  1 02:01 .
drwxr-xr-x  18 u1aryz  staff  612  6  1 02:01 ..
drwxr-xr-x   3 u1aryz  staff  102  6  1 02:01 com

repository/com:
total 0
drwxr-xr-x  3 u1aryz  staff  102  6  1 02:01 .
drwxr-xr-x  3 u1aryz  staff  102  6  1 02:01 ..
drwxr-xr-x  3 u1aryz  staff  102  6  1 02:01 u1aryz

repository/com/u1aryz:
total 0
drwxr-xr-x  3 u1aryz  staff  102  6  1 02:01 .
drwxr-xr-x  3 u1aryz  staff  102  6  1 02:01 ..
drwxr-xr-x  6 u1aryz  staff  204  6  1 02:01 sample-lib

repository/com/u1aryz/sample-lib:
total 24
drwxr-xr-x  6 u1aryz  staff  204  6  1 02:01 .
drwxr-xr-x  3 u1aryz  staff  102  6  1 02:01 ..
drwxr-xr-x  8 u1aryz  staff  272  6  1 02:01 0.0.1
-rw-r--r--  1 u1aryz  staff  298  6  1 02:09 maven-metadata.xml
-rw-r--r--  1 u1aryz  staff   32  6  1 02:09 maven-metadata.xml.md5
-rw-r--r--  1 u1aryz  staff   40  6  1 02:09 maven-metadata.xml.sha1

repository/com/u1aryz/sample-lib/0.0.1:
total 936
drwxr-xr-x  8 u1aryz  staff     272  6  1 02:01 .
drwxr-xr-x  6 u1aryz  staff     204  6  1 02:01 ..
-rw-r--r--  1 u1aryz  staff  457944  6  1 02:09 sample-lib-0.0.1.aar
-rw-r--r--  1 u1aryz  staff      32  6  1 02:09 sample-lib-0.0.1.aar.md5
-rw-r--r--  1 u1aryz  staff      40  6  1 02:09 sample-lib-0.0.1.aar.sha1
-rw-r--r--  1 u1aryz  staff     422  6  1 02:09 sample-lib-0.0.1.pom
-rw-r--r--  1 u1aryz  staff      32  6  1 02:09 sample-lib-0.0.1.pom.md5
-rw-r--r--  1 u1aryz  staff      40  6  1 02:09 sample-lib-0.0.1.pom.sha1

このファイル群を構成そのままでまるまるgh-pagesブランチにコミットしてgithubにプッシュする。以下のようになっていればOK。

ここまで手順通りに進んでいれば以下の記述をbuild.gradleに追記するだけでaarを参照することが出来る。

repositories {
    maven { url 'http://<githubユーザー名>.github.com/<githubリポジトリ名>/repository' }
}

dependencies {
    compile 'com.u1aryz:sample-lib:0.0.1'
}

※Mavenリポジトリと言ってもただのファイル群なので、プロジェクト配下でなくてもいいけど、その場合はmavenのurlは変わる。

ビルド編

今度はgithubにデプロイしたライブラリプロジェクトを参照してビルドしてみる。自分でデプロイしたものを参照したい場合は適宜読み替えて。ここでは俺がデプロイしたやつを使用するでよ。

新規プロジェクトを作成してもいいけど、めんどいのでさっき作成したSampleLibraryプロジェクトにAndroid Applicationモジュールを追加する。

  • Android StudioでFile -> New Module…を選択
  • Android Applicationを選択してNext

ナビ通り進めて作成されたmainモジュールのbuild.gradleにrepositoriesとdependenciesを追記する。

buildscript {
    repositories {
        maven { url 'http://repo1.maven.org/maven2' }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.4'
    }
}

// 追記
repositories {
    maven { url 'http://u1aryz.github.com/Android-NewPopupMenu/repository/release' }
}

apply plugin: 'android'

dependencies {
    compile files('libs/android-support-v4.jar')
    compile 'com.u1aryz:android-newpopupmenu-lib:1.0.1' // 追記
}

android {
    compileSdkVersion 17
    buildToolsVersion "17.0.0"

    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 16
    }
}

プロジェクトを開き直すとAndroid Studioがbuild.gradleを読みなおして以下のようにExternal Librariesに追加されているはずや。(これはちょっとめんどい)

あとは今まで通りライブラリプロジェクトを使用出来る。

終章

自分で手を入れる必要のないライブラリプロジェクトを使用したい場合は、この方法のがスマートだね。例えば、ActionBarSherlockとかを使用したい場合とか。ちなみにActionBarSherlockは4.3.2でGradle対応するのでmavenCentralにアップされるのが待ち遠しいね〜。

2013年5月25日土曜日

Android StudioでRecent Projectのリストをクリアする

Android Studioでいろいろ触りまくっているとRecent Projectがいっぱいになってすごい邪魔になる。IntelliJだとRecent Projectをクリアするメニューがあるんだけど、Android Studioだと見つからなかった。なので、無理やりRecent Projectをクリアする方法をメモ。基本的にはIntelliJで無理やりやる方法と一緒。ちなみにMacね。

以下のファイルを開く
/Users/<username>/Library/Preferences/AndroidStudioPreview/options/other.xml

んで以下のあたりのrecentPathsのlistの中身を消す。
<component name="RecentProjectsManager">
  <option name="recentPaths">
    <list>
      <option value="$USER_HOME$/AndroidStudioProjects/SampleUseLibrary" />
    </list>
  </option>
  <option name="names">
    <map>
      <entry key="$USER_HOME$/AndroidStudioProjects/SampleUseLibrary" value="" />
      <entry key="$USER_HOME$/dev/github/ActionBarSherlock/actionbarsherlock-samples/fragments" value="" />
    </map>
  </option>
  <option name="lastPath" value="$USER_HOME$/AndroidStudioProjects/SampleUseLibrary" />
</component>

以下が修正後。
<component name="RecentProjectsManager">
  <option name="recentPaths">
    <list>
    </list>
  </option>
  <option name="names">
    <map>
      <entry key="$USER_HOME$/AndroidStudioProjects/SampleUseLibrary" value="" />
      <entry key="$USER_HOME$/dev/github/ActionBarSherlock/actionbarsherlock-samples/fragments" value="" />
    </map>
  </option>
  <option name="lastPath" value="$USER_HOME$/AndroidStudioProjects/SampleUseLibrary" />
</component>

2013年1月3日木曜日

Androidで「Unknown error merging manifest」

AndroidでライブラリプロジェクトのAndroidManifest.xmlをメインプロジェクトに自動でマージさせるにはproject.propertiesにmanifestmerger.enabled=trueを加えるだけで良い。 しかし、メインプロジェクトのandroid:targetSdkVersionがライブラリプロジェクトより低いと以下のようなエラーメッセージが表示される。
Unknown error merging manifest
もっとわかりやすいメッセージを表示してほしいよね。

2013年1月2日水曜日

GradleでSlim3 + JPPのビルドスクリプトを書いてみた

Android(アプリ)も新しいビルドシステムとしてGradleを採用したこともあって、流行りに流行りまくっているGradleを試してみた。とりあえず会社でよく使うSlim3 + JsonPullParserのビルドスクリプトを書いてみた。

Gradleでaptを処理する場合はAntタスクを使うらしい。そんでもってSlim3はJava1.5のaptでJPPはJava1.6のaptを使う必要があるらしいので、これまためんどい。

実はこれ、javacのバグによってエラーメッセージが誤って報告されるので気持ち悪い。
もっと良い方法があったら誰か教えて(´・ω・`)

参考資料)

2012年6月3日日曜日

さくらVPSのUbuntu10.04(64bit)にgitolite(g3)をインストール

Ubuntu11ならaptitudeで簡単にインストール出来るみたいだけど、
Ubuntu10.04の場合、アレコレちょっとめんどかったのでインストールログを残しておくことにした。
(それとg3のインストール方法を紹介している日本語のサイトがなかったという理由も)

git-coreのインストール


$ sudo apt-get install git-core

セットアップ準備


1人目のgitolite管理者ユーザーの鍵を予め作成しておく。
$ ssh-keygen -t rsa

gitoliteユーザーを作成する。
$ sudo adduser gitolite

gitoliteユーザーから参照出来る場所に公開鍵を配置する。(あとで削除してね)
$ cp -p .ssh/id_rsa.pub /tmp/ubuntu.pub

gitoliteのインストール / セットアップ


gitoliteユーザーで行う。
$ sudo su - gitolite

githubからクローン
$ git clone git://github.com/sitaramc/gitolite

gitoliteインストール
$ gitolite/install

gitoliteのセットアップを行う。(WARNING出るけど気にしない)
$ export PATH=$HOME/gitolite/src:$PATH
$ gitolite setup -pk /tmp/ubuntu.pub
$ exit

管理用リポジトリをクローン


セットアップ時に指定した公開鍵のユーザーで管理用リポジトリをクローンする。
 (ここでは同サーバなのでlocalhost)
$ git clone gitolite@localhost:gitolite-admin.git

リポジトリを追加する場合はgitolite-admin/conf/gitolite.conf にrepoを追加してプッシュするだけ。 
ユーザーを追加する場合はgitolite-admin/keydir配下に公開鍵を 追加してプッシュするだけ。 
これでリポジトリを追加する作業がgitosisより楽になったー

2012年5月18日金曜日

さくらVPSのUbuntu10.04(64bit)にgit + maven + Jenkinsな環境構築をしてAndroidのCIが出来るまでのメモ

Androidに限らずgit + Jenkins + mavenな環境はよく使うと思うけど、初回のビルドはだいたいこける。
環境が整備出来ていないという理由でね。
ということでAndroidプロジェクトがCI出来るまでにやったことをメモしておく。

Ubuntuインストール・設定


さくらVPSにカスタムOSのUbuntu 10.04をインストール+セキュリティ設定などをした時のメモ
を参考にインストール・設定を行う。
(ここではsshのport変更はやってない)

Jenkinsインストール


Jenkinsをインストールするとjenkinsユーザーが自動で作成されるけどなんとなく先に作っておいた。
$ sudo adduser jenkins
インストールはここを参考に行う。

ビルド環境構築


openjdk-6-jdkとmavenをインストールする。
$ sudo apt-get install openjdk-6-jdk
mavenインストールはここを参考に行う。

Android SDKインストール


まず、32ビット版のソフトを動かすためにia32-libsをインストールする。(ハマりポイント)
$ sudo apt-get install ia32-libs

jenkinsユーザーから実行出来るようにする必要があるのでjenkinsユーザーで行う。
$ mkdir -p /var/lib/jenkins/tools
$ cd /var/lib/jenkins/tools
$ wget http://dl.google.com/android/android-sdk_r18-linux.tgz // バージョンは適宜変更
$ tar zxvf android-sdk_r18-linux.tgz
$ ./android-sdk-linux/tools/android update sdk -u

gitosisインストール・設定


まず、gitosisをインストールする。今までapt-getで今回はaptitudeだけど気にしないw
$ sudo aptitude install gitosis

gitosisの初期化の際に一人目の管理者の公開鍵が必要なのでgitosisユーザーから見える箇所に配置する。
(ここでは同サーバー内のubuntuユーザーを一人目の管理者とする)
$ cp -p /home/ubuntu/.ssh/id_rsa.pub /tmp/.
$ sudo su - gitosis
$ gitosis-init < /tmp/id_rsa.pub

gitリポジトリ作成


gitosis管理者ユーザーで管理情報リポジトリをクローンする。(クローン済みならpullする)
$ git clone gitosis@ホスト名:gitosis-admin.git

gitosis.confを修正する。(XXXXは任意ユーザー)
[gitosis]
loglevel=DEBUG

[group gitosis-admin]
writable = gitosis-admin
members = XXXX

[group リポジトリ名]
writable = リポジトリ名
members = XXXX jenkins

修正が終わったらjenkinsユーザーのssh公開鍵をkeydir配下に配置する。
(ssh公開鍵はパスフレーズなしで作成)
コミットしてプッシュしたら実際にリポジトリを作成する。
$ cd /srv/gitosis/repositories
$ sudo mkdir リポジトリ名.git
$ cd リポジトリ名.git
$ sudo git init --bare --shared=true
$ sudo chown -R gitosis:gitosis ./

jenkinsユーザーまたはmembersに記載した任意のユーザーから以下コマンドを実行してクローン出来ることを確認する。
$ git clone gitosis@ホスト名:リポジトリ名.git

Jenkinsセットアップ


jenkinsユーザーがGitリポジトリと通信するためknown_hostsに追加する必要がある。(重要)
(ここではGitリポジトリとJenkinsが同サーバ)
$ sudo -u jenkins ssh gitosis@localhost // yesを答える

続いてクローン時に必要になるgitconfigの設定を行う。
$ sudo su - jenkins
$ git config --global user.email "jenkins@jenkins-server"
$ git config --global user.name "jenkins"

http://your-jenkins-server:8080にアクセスする。
Jenkinsの管理 -> プラグインの管理から以下の3つを選択してインストールする。
  • Git plugin
  • Android Emulator Plugin
  • Android Lint Plugin
続いてJenkinsの管理 -> システムの設定から以下を設定する。
  • Android
    • Android SDK root : /var/lib/jenkins/tools/android-sdk-linux
  • Maven
    • Name : Default(任意)
    • MAVEN_HOME : /usr/local/maven

ビルドしてみる


上記で作成したリポジトリにプロジェクトを追加してプッシュする。
android-archetypesのandroid-with-testを使用してプロジェクトを作成する。
正常に作成出来たらリポジトリにプッシュする。(Jenkinsからクローン出来るように)
mvn archetype:generate \
  -DarchetypeArtifactId=android-with-test \
  -DarchetypeGroupId=de.akquinet.android.archetypes \
  -DarchetypeVersion=1.0.8 \
  -DgroupId=your.group \
  -DartifactId=your-project-name \
  -Dpackage=your.package

http://your-jenkins-server:8080にアクセスし新規ジョブ作成よりMaven2/3プロジェクトのビルドのジョブを作成する。

ソースコード管理システムでGitを選択し、Repository URLにgitosis@ホスト名:リポジトリ名.gitを入力する。

ビルドのルートPOMにリポジトリから見たルートのpom.xmlのパスを入力する。
ゴールとオプションにinstallを入力する。
ビルド環境の"Run an Android emulator during build"にチェックを入れ、エミュレーターの設定項目を入力する。
"Show emulator window"のチェックを外す。(重要)
ビルド後の処理の追加をクリックして成果物を保存を選択する。
保存するファイルにメインプロジェクトのapkを指定すればいい。
保存、ビルド実行して"Finished: SUCCESS"がコンソールに出力されればOK。
最後に成果物としてapkが存在していれば完了〜