phicdy devlog

Androidアプリ開発やその他技術系の記事をたまに書きます

AndroidとかiOSとかモバイル多め。その他技術的なことも書いていきます。

Alfredからビルドする

最近、なるべくマウスから手を離したくないなーと思ってなんでもかんでもターミナルでコマンドなりシェルスクリプトでやろうとしている。

ビルドに関してもオプションを受け取れるようにして、シェルスクリプトで切り替えているのだけども、実行するには一回ターミナルを開いて実行して終わったら元の画面に戻って・・・ということになるので、なるべく開きたくない。

これをAlfredでなんとかならないかなと試行錯誤してできるようになったのでメモ。

環境

Alfredとは

AlfredはMac用のランチャーアプリ。バックグラウンドで常駐し、option+spaceでいつでもどこからでも起動できる。

www.alfredapp.com

AlfredのUI自体はただの入力欄で、起動するとフォアグラウンドに出てきて、アプリの頭文字を入力することで素早くアプリを起動できる。

f:id:phicdy:20150407235051p:plain

Alfredのいいところはいつでもどこからでも起動できるというところで、どんな作業をしていようとアプリを起動できる。

またアプリ起動だけでなく、Google検索やファイル検索といった検索機能もカスタマイズして利用できる。

今回はビルドを行うアプリケーションを作成して、それをAlfredから起動することで、いつでもどこからでもビルドができるようにした。

そのビルドを行うアプリケーションを簡単に作れるのがMacに標準で入っているAutomatorである。

Automatorの設定

Automatorでは開始の通知の表示とビルドスクリプトの実行、 そして終了の通知の表示を行うだけである。

まず、Automatorを開き通知を右の欄にドラッグする。

f:id:phicdy:20150418170039j:plain

タイトル等は適当に。

次にシェルスクリプトの実行をドラッグする。 ここでの注意点として、Automatorからシェルスクリプトを実行する際、bash_profileが読み込まれないので、明示的に読み込む必要がある。

f:id:phicdy:20150418170100j:plain

最後にもう一度通知を追加して保存する。

f:id:phicdy:20150418170125j:plain

保存先は、Alfredの検索対象(/Applicationsなど)となっているフォルダにする。

Alfredから起動できるようになる。

f:id:phicdy:20150418194536j:plain

通知は右上に出る。

f:id:phicdy:20150418194609j:plain

通知がすぐ消えるのを変えたい場合は、設定から通知を通知パネルに変更すれば、自分で消すまでは残り続ける

f:id:phicdy:20150418194623j:plain

おわりに

Alfredからビルドできるようになったけど、ビルド対象やビルドオプションが増えるたびにAutomatorで設定する必要があるのどうにかならないかな。。。

JenkinsのJUnitでNoClassDefFoundError

JUnitの結果のXMLファイルがなぜかNoClassDefFoundErrorで読めなかったが、解決したのでメモ。

環境

エラーと原因

エラーは以下の通り。

Process leaked file descriptors. See http://wiki.jenkins-ci.org/display/JENKINS/Spawning+processes+from+build for more information
Recording test results
ERROR: Publisher hudson.tasks.junit.JUnitResultArchiver aborted due to exception
java.lang.NoClassDefFoundError: hudson/tasks/junit/JUnitParser$ParseResultCallable
     at hudson.tasks.junit.JUnitParser.parseResult(JUnitParser.java:90)
     at hudson.tasks.junit.JUnitResultArchiver.parse(JUnitResultArchiver.java:120)
     at hudson.tasks.junit.JUnitResultArchiver.perform(JUnitResultArchiver.java:137)
     at hudson.tasks.BuildStepCompatibilityLayer.perform(BuildStepCompatibilityLayer.java:74)
     at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20)
     at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:770)
     at hudson.model.AbstractBuild$AbstractBuildExecution.performAllBuildSteps(AbstractBuild.java:734)
     at hudson.model.Build$BuildExecution.post2(Build.java:183)
     at hudson.model.AbstractBuild$AbstractBuildExecution.post(AbstractBuild.java:683)
     at hudson.model.Run.execute(Run.java:1770)
     at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
     at hudson.model.ResourceController.execute(ResourceController.java:89)
     at hudson.model.Executor.run(Executor.java:240)

 

調べた結果以下のページで解決した。 

[#JENKINS-26060] Using Jenkins 1.583. Today updated plugins, junit publisher now crashes. - Jenkins JIRA

The problem is that JUnit 1.3 is actually incompatible with Jenkins before 1.587 except 1.580.1 LTS. Unfortunately this cannot be expressed through dependencies, and to make it available to LTS users, it'll also be made available to users on weeklies >1.580.


どうもJenkinsのバージョンが1.587より古く、JUnitプラグインのバージョンが1.3だと不具合が出てしまうらしい。 

私の環境ではJUnitプラグインのバージョンは1.5だったが、同様の問題が発生したので、1.3以降なら起きるのかもしれない(未検証)。


解決方法

Workarounds:
・Downgrade JUnit to 1.2
・Downgrade/cross-grade Jenkins to 1.580.1 LTS
・Upgrade Jenkins to 1.587 or higher
As this only affects older weekly releases between 1.580 and 1.586, it's not worth the effort to fix. The general expectation is that users keep their instance fairly close to the current release when using the weeklies.  


JUnitのバージョンを下げるか、Jenkinsのバージョンを1.580.1にするか1.587以上にすればいいとのことなので、Jenkinsのバージョンを最新版にして解決。

# 一応バックアップ
$sudo mv /usr/share/jenkins/jenkins.war /usr/share/jenkins/jenkins.war.1.581
# Jenkinsの設定画面からダウンロード
$sudo cp /home/hoge/Download/jenkins.war /usr/share/jenkins/
# 再起動
$sudo /etc/init.d/jenkins restart


というかJenkinsの管理画面でアップデートしろとずっと出ていたのを無視していたのがよくなかったな。。。  

mitmproxyで端末の通信内容を見る

mitmproxyとは

mitmproxyはコンソール型の通信監視ツールである。

mitmproxyは、プロキシを通じて通信サーバと端末の間に入り、その通信内容を表示する。

mitmproxy - home

f:id:phicdy:20150530154256p:plain


例えばモバイルのアプリケーションを開発している際に、端末から実際に行っている通信内容を確認したいときがある。

ログなどに出力すれば見ることはできるが、細かい情報を見ようとするならば実際に通信内容を見るしかない。

mitmproxyを使えば、リアルタイムに通信内容を確認できる。

今回はVirtualBox上のUbuntuにインストールして、Androidの通信を見てみた。

環境

 

インストール

pipを使ってインストールできる。

RUN apt-get -y update

# Install pip
sudo apt-get -y install python-dev
sudo apt-get -y install libxml2-dev
sudo apt-get -y install libxslt1-dev
sudo apt-get -y install zlib1g-dev
sudo apt-get -y install libffi-dev
sudo apt-get -y install libssl-dev
sudo apt-get -y install python-pip

# Install mitmproxy
sudo pip install mitmproxy

 

準備

端末

Androidの場合、Wi-Fi設定にてプロキシを設定できるのは3.2 以上のみである。

まず端末とmitmproxyの入ったUbuntuを同ネットワーク上に繋ぐ。

次に端末のWi-Fi設定から接続しているSSIDを長押しする。

そして「ネットワークを変更」から「詳細オプションを表示」にチェックを入れてプロキシを設定する。

プロキシのホストはUbuntuIPアドレス、ポートは自由に設定できる。

 

証明書のインストール

mitmproxyを使うと、mitmproxyを通じて通信を行うことになるので、端末に証明書をインストールする必要がある。

まずmitmproxyを起動する。デフォルトのポートは8080なので、プロキシのポートを8080以外に設定した場合は、-pオプションで変更する。

mitmproxy -p 8001

証明書をインストールする方法は2つある。

  • http://mitm.it にアクセスする。
  • adb pushで証明書を端末に直接入れてインストールする。

http://mitm.it にアクセスする際はmitmproxyを起動しておかないと接続できない。

証明書はmitmproxyを1度実行後、~/.mitmproxy/mitmproxy-ca-cert.cer に置かれるのでこれをadb pushで端末に入れる。

証明書を端末に入れた後は、設定 -> セキュリティ -> ストレージからインストール でインストールできる。

 

使い方

mitmproxyはコンソールで操作するツールになっている。

左にカーソルがあり、見たい通信のところでEnterキーを押すことで詳しい中身が見れる。

下の画像はAmazonにアクセスしたときのリクエスト内容である。

f:id:phicdy:20150530154314p:plain


tabキーを押すことでサーバからのレスポンスを確認できる。

f:id:phicdy:20150530154323p:plain

 

その他にも通信内容を変更して送り返したり、通信のフィルタリングを行ったりといろいろな機能がある。

下記記事に詳しい使い方が書いてある。

モバイルアプリ開発者のための mitmproxy 入門 - Qiita

【Android】API16のuiautomatorでNoSuchMethodError


uiautomatorでNoSuchMethodErrorが発生して困っていた問題が解決したのでメモ。

発生までの流れ

http://www.atmarkit.co.jp/ait/articles/1410/07/news029.html

に従ってテストプロジェクトを作り、ターゲットは、API16(4.1, 4.1.1)としていた。 そして(Android SDK)/platforms/android-16のuiautomator.jarを使っていた。

このテストプロジェクトでテストを作成し、API 17(4.2)の端末で実行したところ、NoSuchMethodErrorが発生してしまっていた。


原因

UiScrollableのsetAsVerticalList()の定義がAPI16とAPI17で変わっていた。

//4.1.1
public void setAsVerticalList()

//4.2
public UIScrollable setAsVerticalList()

参考:http://stackoverflow.com/questions/15204154/uiautomator-failing-on-4-1-2-device



今回はScrollViewの中身のViewを取得するために、UiScrollableのインスタンスを作り、setAsVerticalList()を設定していた。

UiScrollable scrollableView = new UiScrollable(new UiSelector().className(ScrollView.class.getName()).scrollable(true));
if (!scrollableView.exists()) {
    fail("scrollview does not exist");
}
scrollableView.setAsVerticalList();


メソッド名が同じで返り値を使っていたわけではないので、ビルドは普通に通る。 だがAPI17で実行しようとするとビルド時の定義と実際に呼ばれるメソッドが異なるためNoSuchMethodErrorが出ていたのかと思われる。

おわりに

悩んだ理由として、Android Developerのページには特にAPI Levelが書いていなくて困った。

変更したことを書いていて欲しい。

http://developer.android.com/tools/help/uiautomator/UiScrollable.html#setAsVerticalList%28%29

【Android】ActionBarから検索して別Activityで結果を表示する

検索してもなぜか、同じActivityで受け取る例ばかり出てくるので、自分のメモ用に。

検索を行うActivityをDoSearchActivity、検索結果を受け取るActivityをSearchResultActivityとする。

AndroidManifest

検索を行う側(DoSearchActivity)にandroid.app.default_searchableという名前のmeta-dataを追加する。
そしてvalueに検索結果を受け取るActvityを指定する

検索結果を表示するActivityも同様にmeta-dataを追加するが、こちらはandroid.app.searchableという名前にしてXMLのリソースを指定する。
そして、ActionBarから検索が行われたときにintentを受け取れるようにandroid.intent.action.SEARCHのアクションをintent-filterに追加する

<activity
	android:name="xxx.xxx.xxx.DoSearchActivity"
	android:configChanges="orientation|keyboardHidden|screenSize"
	android:label="@string/app_name" >
	<meta-data
    		android:name="android.app.default_searchable"
     		android:value="xxx.xxx.xxx..SearchResultActivity" />
</activity>
<activity
	android:name="xxx.xxx.xxx.SearchResultActivity"
	android:configChanges="orientation|keyboardHidden|screenSize"
	android:label="@string/app_name" >
	<meta-data
    		android:name="android.app.searchable"
		android:resource="@xml/searchable" />
    	<intent-filter>
		<action android:name="android.intent.action.SEARCH" />
     	</intent-filter>
</activity>

検索結果を表示するActivityのmeta-dataにて指定したXMLは以下のようにする。

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
        android:label="@string/app_name"
        android:hint="@string/search" />


android:hintを指定することで検索バーをタップした時に表示する文字を指定できる。


http://developer.android.com/images/ui/actionbar-searchview@2x.png

Action Bar | Android Developers


DoSearchActivityのActionBarに検索バーを設置する

DoSearchActivityのメニューファイルに検索バーを追加することでActionBarに検索バーを表示できる。
Android SDKにSearchViewというクラスが用意されているのでそれを利用する。

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/search"
        android:actionViewClass="android.widget.SearchView"
        android:icon="@drawable/ic_action_search"
        android:showAsAction="collapseActionView|ifRoom"
        android:title="@string/search"/>
</menu>

よく見る検索のアイコンはGoogleが公式で配布しているので、ダウンロードして利用する。

Iconography | Android Developers


DoSearchActivityの設定

DoSearchActivityでは、メニューの設定でSearchViewを初期化する。
デフォルトの設定では、キーボードを閉じても検索バーが閉じてくれない。

そのため、OnFocusChangeListenerをセットしてフォーカスが他に移ったら検索バーを閉じるという処理を入れている。

参考:
android - Auto Collapse ActionBar SearchView on Soft Keyboard close - Stack Overflow

@Override
public boolean onCreateOptionsMenu(Menu menu) {
	MenuInflater inflater = getMenuInflater();
	inflater.inflate(R.menu.menu_do_search, menu);

	// SearchViewの初期化
	SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
	final MenuItem searchMenuView = menu.findItem(R.id.search);
	searchView = (SearchView)searchMenuView.getActionView();
	searchView.setSearchableInfo(searchManager
			.getSearchableInfo(getComponentName()));

	// 検索バーからフォーカスが移ったら、SearchViewを終了して空の文字列で検索する
	searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
        	@Override
        	public void onFocusChange(View view, boolean queryTextFocused) {
          		if(!queryTextFocused) {
            			searchMenuView.collapseActionView();
                		searchView.setQuery("", false);
            		}
        	}
    	});
	
	return true;
}



SearchResultActivityで検索結果を表示する

ユーザがキーワードを入れて検索をすると、Intentにそのキーワードが入る。

キーはSearchManager.QUERYなので、Intent#getStringExtra()にそのキーを指定することでユーザが入力したキーワードが取得できる。

あとはそのキーワードから検索を行い結果を表示すればよい。

Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
	String keyword = intent.getStringExtra(SearchManager.QUERY);

	// keyword を使ってデータベースから検索などをして結果を表示
}

SmartWatch 3を1ヶ月使ってみて

f:id:phicdy:20150530154646j:plain

前月ソニーモバイルコミュニケーションズから発売されたAndroid Wear端末のSmartWatch3を買いました。

SmartWatch 3を買いました - pluea engineering blog

SmartWatch3 SWR50 | ソニーモバイルコミュニケーションズ

だいたい1ヶ月くらい使ってみたので感想を書いていきたいと思います。

スマホで通知を見る回数が減った

Android Wearではスマホに来た通知をリアルタイムに受け取ることができます。

今まではスマホが振動する度に、

  1. スマホの電源をつける
  2. ロックを解除
  3. 通知領域を開いてなんの通知が来たのか確認
  4. 通知が必要なければ消す or 中身を見る

という流れでした。

Android Wearでは、スマホに通知が来ると時計が震え盤面に通知を知らせてくれます。そしてロックの解除が必要ないので、

  1. 時計を目の前に持ってくる
  2. 通知が必要なければ消す or 中身を見る

だけで通知を処理できます。

SmartWatch3の独自機能なのかAndroid Wearの機能なのかわかりませんが、腕を目の前に持ってくる動きをすると自動で盤面の電源が入ります。

なので、盤面が消灯していても盤面をタップすることなく盤面を明るくすることができます。この機能も結構便利です。

また、時計は常に腕につけているので、通知に気が付きやすいのも良い点です。

通知が必要なければスワイプで簡単に消すことが出来ます。もちろんAndroid Wear側で通知を消せば、スマホ側でも消えています。

通知を見る場合はアプリにもよりますが、対応していればAndroid Wear側で見ることができます。例えばGmailはタップすることでメールの中身を見れます。また地味に便利なのが、スマホでは2件以上メールが来ると通知がまとめられてしまって、Gmailアプリを開くしかないのですが、Android Wearではメール1つ1つを見ることができます。

対応していない場合はスワイプして「端末で開く」を選択してスマホ側で見る流れになります。

バッテリーについて

SmartWatch 3はサイズの小ささもあってバッテリー容量がそれほどあるわけではありません。

公式では約2日となっています。

また、連携するスマホ側では、Android Wearの機能をフルで使うためにGPSBluetoothを常にオンにしています。

1ヶ月使ってみたのですがスマホ・SmartWatch共にバッテリーで困ったことは特にありませんでした。

まずSmart Watch 3ですが、使う時間によるとは思うのですが、帰宅して外したときにバッテリー残量を見てみるとだいたい60~70%くらい残っています。

もしバッテリーが切れたとしても1時間でフル充電できるので、いざという時はモバイルバッテリー等で充電すればそれほど困りません。

ただ、ほぼ毎日充電する手間があるのと、充電の端子が刺しづらいという問題もあります。

f:id:phicdy:20150530154658j:plain

次にスマホ側ですが、Bluetoothの新規格であるBluetooth Low Energyが優秀なのかさほどバッテリー消費量は増えませんでした。

体感ですが、10%程度の増加でしょうか。

GPSに関しても常にGPSを使った処理をしているわけではないので、こちらもあまり影響はありませんでした。

ただ、常に位置情報を取得できる状態にあるので、その点は注意しないと余計な位置情報を漏らす可能性があります。

アプリについて

Android Wearに対応しているアプリがどの程度揃っているかによって使い心地が変わってくると思うのですが、 現状では概ね満足しています。

私が特に使っているのは

Wear Mini Launcher - Google Play の Android アプリ

=> Launcherを追加する

Yahoo!乗換案内 無料の時刻表、運行情報、乗り換え検索 - Google Play の Android アプリ

=> 電車の検索

Wear for Swarm - Google Play の Android アプリ

=> Foursquareのチェックイン

Wearable Widgets - Google Play の Android アプリ

=> Androidウィジェットを表示

です。

特にWear Mini Launcherは便利で、左からスワイプすることでアプリ一覧画面を開くことができるので、アプリへのアクセスが格段によくなります。

そもそもAndroid Wearのアプリ一覧へのアクセスがかなり悪いです。

アプリ一覧にアクセスするには、盤面をタップして一番下までスクロールし、「開始」を押さなければなりません。出てくるアプリ一覧も一行に一つなので非常に見難いです。

Wear Mini Launcherを入れることで、この辺りがかなり改善されました。

Yahoo!乗換案内は、予め経路を登録しておくことで現在時刻の経路をすぐに検索することができます。

急いでいるときなど、スマホを開いてアプリを開いて・・・というよりもかなり早く電車時刻の検索ができます。

最後に

Smart Watch3には概ね満足しています。これからも使い続けていこうと思います。

先週辺りにアップデートがきて、盤面のカスタマイズのAPIが使えるようになったので、ますます対応アプリが増えてくるかと思います。

まだまだAndroid Wearを使ってできることがあると思うので、新しい使い方を模索していこうと思います。

SmartWatch 3を買いました

f:id:phicdy:20150530185308j:plain

11/28にソニーからSmartWatch 3が発売されたので早速買ってきました。

SmartWatch3 SWR50 | ソニーモバイルコミュニケーションズ

値段はビックカメラで26870円でした。

予約なしで買えるのかなと少し思いましたが、普通に買えました。 ただ、あまり広告にやる気がなく、ビックカメラではモックしかなかったのでヨドバシで実機を見てから買いました。

外観と付属品

ディスプレイは1.6インチで小さめです。

時計なのでこのくらいのサイズでちょうどいいかと思います。

小さすぎてタッチがしにくいといったことはなかったです。

f:id:phicdy:20150530185325j:plain

ディスプレイの裏側です。

こちらに充電を行うmicroUSBポートがあります。

f:id:phicdy:20150530185341j:plain

バンドはゴム製になっています。

留め具のところは金属になっていてパチっとはめるだけで簡単に取り外しできるようになっています。

f:id:phicdy:20150530185351j:plain

付属品は以下の通りです。

  • SMART STYLEキャンペーンの申し込み用コード
  • 説明書
  • 保証書
  • microUSBケーブル(短め)

f:id:phicdy:20150530185401j:plain

SMART STYLEキャンペーン

私は店頭で知ったのですが、2014年11月28日(金)10:00 から 2015年1月14日(水)23:59 まで対象のXperiaを持っているとEdy5000円分がもらえるキャンペーンを行っています。

SMART STYLEキャンペーン | Xperia™ Store

Xperia Zシリーズを持っている方であれば、誰でももらえるようなので持っている方は期間内に買うと非常にお得かと思います。

設定

SmartWatch 3を起動するとまず言語設定を聞かれます。

日本語もあるので、日本語にしておきます。

f:id:phicdy:20150530185417j:plain

次にAndroid Wearをペアリングする端末にインストールするように表示されます。

f:id:phicdy:20150530185430j:plain

Google PlayAndroid Wearというアプリがあるのでそれをペアリングする端末にインストールして開きます。

f:id:phicdy:20150530185442p:plain

f:id:phicdy:20150530185454p:plain

あとはアプリの指示に従っていけば設定が完了します。

特に戸惑うことはなくスムーズにペアリングを行うことができました。

Bluetoothや位置情報設定などをオンにしておくと楽かと思います。

チュートリアル

設定が終わるとSmartWatch 3側でチュートリアルが始まります。

正直使い方が全然わからなかったので非常に助かりました。

f:id:phicdy:20150530185506j:plain

まず上にスワイプするように表示されます。

スワイプすると設定が完了した旨が表示されます。

f:id:phicdy:20150530185521j:plain

もう一度上にスワイプします。

f:id:phicdy:20150530185536j:plain

どうやらAndroid Wearではカードという単位で天気や通知などが表示されるようです。

f:id:phicdy:20150530185546j:plain

不要なカードは右にスワイプすることで削除できます。

f:id:phicdy:20150530185555j:plain

画面を暗くしたいときには手で覆えばいいようです。