弊社BPSで開発しておりますAndroid端末向け音楽試聴アプリMusicFlyを先ほど1週間ぶりにアップデートしました。
今回のアップデートにより
XperiaMiniに代表される低解像度端末や、反対の高解像度端末などへの対応を果たし
全スクリーンサイズ対応のアプリケーションとなりました。
技術者向けの参考情報
また、以前より原因が解明できずにいたバグのいくつか解決することができました。
そのうちの一つがAndroid1.5でのみタブを利用した画面で強制終了してしまうクリティカルなバグであり、
今回無事解決しました。技術者向けの詳しい話はこちらで。
該当端末を利用している方にはご不便おかけしました。
Androidで便利な、タブ表示。

タブ表示
これは、TabActivity, TabHost, TabSpecを使って簡単に実現できます。
src/MainActivity.java
package jp.bpsinc.android.tabtest;
import android.app.TabActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.widget.TabHost;
import android.widget.TabHost.TabSpec;
public class MainActivity extends TabActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TabHost tabHost = getTabHost();
LayoutInflater.from(this).inflate(R.layout.main, tabHost.getTabContentView(), true);
//タブを作る
TabSpec tab1 = tabHost.newTabSpec("tab1");
tab1.setIndicator("tab1");
tab1.setContent(R.id.tab1);
TabSpec tab2 = tabHost.newTabSpec("tab2");
tab2.setIndicator("tab2");
tab2.setContent(R.id.tab2);
tabHost.addTab(tab1);
tabHost.addTab(tab2);
}
}
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="TAB1" android:id="@+id/tab1" />
<TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="TAB2" android:id="@+id/tab2" />
</FrameLayout>
しかし、サンプルでなく複雑なアプリを作ると、Android 1.5 (SDK Version 3) の時だけ、StackOverflowErrorが発生するという現象に見舞われることがあります。
body : java.lang.StackOverflowError
at android.text.TextUtils#getChars:69
at android.graphics.Canvas#drawText:1278
at android.text.Layout#draw:337
at android.widget.TextView#onDraw:3921
at android.view.View#draw:5838
at android.view.ViewGroup#drawChild:1486
at android.view.ViewGroup#dispatchDraw:1228
at android.view.ViewGroup#drawChild:1484
at android.view.ViewGroup#dispatchDraw:1228
at android.view.ViewGroup#drawChild:1484
at android.view.ViewGroup#dispatchDraw:1228
at android.view.ViewGroup#drawChild:1484
at android.view.ViewGroup#dispatchDraw:1228
at android.widget.AbsListView#dispatchDraw:1319
at android.widget.ListView#dispatchDraw:2820
at android.view.View#draw:5944
….
こちらのGoogleGroupディスカッションでも触れられているようですが、Android 1.5では、タブの中に多重にネストしたコンテンツがあると、StackOverflowErrorが発生します。
手元のエミュレータで試したところ、12回ネストしたところで、エラーになりました。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="TAB1" android:id="@+id/tab1" />
<FrameLayout android:id="@+id/tab2" android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
<TextView android:text="TAB2" android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</FrameLayout>
</FrameLayout>
XMLをパーツに分けて書いていると、うっかり12回を超えてしまうことがあるので、注意が必要です。
解決策としては、ネスト回数を減らすか、Android 1.5を対象から外すという後ろ向きなものが最適ですね。
MusicFlyなどの弊社Androidアプリで、SDカードを使うようには見えないのに
ストレージ:SDカードのコンテンツを修正・削除する
のパーミッションが付与されていて、不安に思う方がいらっしゃったようです。
技術的な話ですが、該当のWRITE_EXTERNAL_STORAGEは、API Level 4(Android 1.6)以上で追加されたもので、Android 1.5の時には、パーミッション無しでSDカードに書き込めました。
Androidでは後方互換性のために、TargetをAndroid 1.5にしたアプリを1.6以上で動かすと、自動的にWRITE_EXTERNAL_STORAGEパーミッションが付与される、というようになっています。
これが、やたら多くのアプリが「ストレージ」パーミッションを要求する理由ですね。実際には書き込みしていないです。
ちなみに、MusicFlyでそれぞれのパーミッションの利用方法は以下の通りです。
READ_PHONE_STATE : 着信時に音楽を停止する機能で利用
KILL_BACKGROUND_PROCESSES、RESTART_PACKAGES : メニューから「終了」を実施するために利用
KILL_BACKGROUND_PROCESSESは、自分だけを終了したいのに範囲が広すぎますね。
Froyo以上対応にすればもう少しましな解決ができるんでしょうけど・・・。悩ましいです。
※MusicFlyではXperia miniなどのQVGA端末に対応するため、Targetを1.6にしつつ1.5でも動作するように調整しています。
そのため、次期バージョンでは、「ストレージ」パーミッションが消えているかもしれません。MusicFly2.3をお楽しみに!
音楽試聴AndroidアプリケーションMusicFlyが先日公開されたバージョン2.2.0より、他のアプリから呼び出すことが可能になりました。
アーティスト名もしくはアルバム名を受け取ってその検索結果一覧画面を表示させることができます。

他アプリケーション →

MusicFly
右の画像はサンプルアプリケーションから【hoge】という単語でMusicFlyにアーティスト検索を起動させています。
サンプルアプリケーションのコードを載せておきますので、参考にしていただいて、ぜひとも素晴らしいアプリを開発してください。
// 入力フィールド
final EditText editText = (EditText) findViewById(R.id.text);
// アーティスト検索ボタン
final Button artistBtn = (Button) findViewById(R.id.btn_artist);
artistBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 入力フィールドのテキストを取得
String input = editText.getText().toString();
// アーティスト検索を実行
Uri uri = Uri.parse(String.format("musicfly://search?type=artist&name=%s", input));
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
});
// アルバム検索ボタン
final Button albumBtn = (Button) findViewById(R.id.btn_album);
albumBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String input = editText.getText().toString();
Uri uri = Uri.parse(String.format("musicfly://search?type=album&name=%s", input));
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
});
先ほど音楽試聴Androidアプリ MusicFlyをバージョン2.2にアップデートしました!!
新バージョンの主な特徴は、
- 楽曲の購入をより分かりやすく
- Tweitterとの連携を強化
- 他アプリからの起動が可能
となっています。

楽曲の購入をより分かりやすく
楽曲の購入をより分かりやすく
MusicFlyは音楽試聴アプリであり、試聴していただき気に入ったものがあれば購入していただくことを目的としています。
しかし、ユーザーの方々から購入遷移がわかりずらいとの声をいただき、それを解消するため、今回のアップデートでより分かりやすい仕組みを導入しました。気に入ったアルバムがあれば再生画面の【Buy Now】ボタンからお願いします。

Tweitterとの連携を強化
Tweitterとの連携を強化
MusicFlyの主な機能のひとつに気にいったアーティスト、アルバムをお気に入りとしてブックマーク登録できるというものがあります。そして、TwitterとMusicFlyの連携を許可していれば、お気に入り登録時に自動でその旨をつぶやくことができました。
今回のアップデートではこのTwitterとの連携を強化し、お気に入り登録時にTweetするのかしないのか、するならばそのメッセージ内容を編集できるようになりました。

他アプリからの起動が可能
他アプリからの起動が可能
Twitterのあるユーザーさんの発言がきっかけとなり、開発しました。
他アプリから検索キーワードをMusicFlyに投げると、その検索結果を表示できます。
詳しい利用方法は後日別の記事にまとめます。
謝辞
気がつけばMusicFlyもバージョン2.2となり、初期開発から数えると半年以上のプロジェクトとなってきました。ここまでこれたのも、応援、ご協力していただいている多くの皆さまのおかげであり、感謝の次第であります。
そして、今後もよりよいサービスを提供できるよう、ますますの応援、ご協力をよろしくお願いします!!
弊社で開発していおりますAndroidアプリ MusicFlyとカタぞうではバグ報告システムによって収集しているデータがそこそこの量になってきたので、このたび、グラフとして現在のAndroid情勢を比較してみました。
バグ報告システムとは何ぞやという方はこちらの記事をどうぞ。
この仕組みを参考にさせていただきました。
*注 データとしてあまり信頼はしないでください。あくまで参考程度に。
デバイスのシェア

SDKのバージョン

インプレッション表示の収入がないとか、クリック単価が低いとか、なかなか広告が出ないとか、アプリ・Web開発者側からするとお金にしづらいAdMobではありますが、すごく使いやすいので、使っている方も多いと思います。
Androidに完全対応した(少ない手間で組み込める)数少ない広告システムということもあり、色々お世話になります。
今回は、AdMobの登録~Androidで広告を表示してみるまでの簡単な手順と、注意点です。
登録
http://jp.admob.com/から登録します。
アプリケーションを追加
ログインしたら上部タブから「マーケットプレイス」を選択します。
「キャンペーン」は広告主用のものなので、開発者は「サイト及びアプリケーション」を開きます。
「サイト・アプリケーションを追加」ボタンをクリックし、「Android」ボタンをクリックすると、アプリ情報入力画面になります。
ここに入力した内容に間違いがあっても、広告が表示されない、ということはありませんが、なるべく正直に入力しましょう。
SDKのダウンロード
アプリの登録を完了すると、SDKとマニュアルPDFがダウンロードできるようになります。
SDKはダウンロード・解凍して、適当な場所に置いておきます。同フォルダにAdMobSDKのリファレンス(JavaDoc)もあるので、是非参考にしてください。
これ以降の手順は、PDFに従うのが一番です!!
広告が表示されないとき
ということで、解説を途中で放棄して、「PDF通りにやったのに広告が表示されない」という場合のチェックポイントです。
基本的に、ManifestにパブリッシャーIDを入れて、attrs.xml、表示したいViewのXMLを書けばOKなのですが、以下の場合、広告が表示されません。
・ネットワーク接続できない
この場合、広告は取得できず、何も表示されません。
・表示領域が狭い
AdViewのサイズは、横幅320px以上である必要があります。それより小さいと、何も出てきません。
・ログに「no ads are available」と出る場合
広告がありません。AdMobは広告主に比べて開発者が多いのか、広告が見つからないことが良くあります。
この場合、Webの管理画面から「自社広告」を入れておけば、何も見つからないときに自社広告を表示することができます。
・単に遅い
Viewが表示されてから広告が表示されるまで、数秒かかるのが普通です。
上部に入れる場合は、48pxくらいの高さを確保しておいた方が、レイアウトが変わらなくて良いかもしれません。
動的にキーワードフィルタする
Web管理画面から、表示する広告のジャンル、キーワードフィルタ等を設定することができます。
しかし、アプリのコードから指定すれば、現在表示しているコンテンツにマッチした広告を表示することも可能です。
以下のようなコードで可能です。
AdView ad = (AdView)findViewById(R.id.ad);
ad.setKeywords("music");
とても多機能なAdMob、うまく使いこなしたいですね。
Androidは多言語対応が簡単で、
values/strings.xml
values-ja/string.xml
などの言語ファイルを作るだけで、システムロケールにあわせて自動的に多言語対応されます。
しかし、開発しながらstrings.xmlを書いていくと、複数言語を管理するのはかなり大変。
また、開発者以外の翻訳者にXMLを書かせるのも酷な話です。
ということで、万能ツールExcel君の出番です。
簡単なVBAスクリプトで、Excel管理している言語ファイルから、strings.xmlを出力する機能を作りました。
(たぶん似たようなことをやっている方は多いですよね・・・)

言語ファイル
これを使えば、
・日本語にはあるのに英語には無い!などの、strings.xmlの記述ミスが無くなります
・Excelなので、XMLを分からない人にも翻訳をお願いできます
・一括生成で、スピーディーに言語のアップデートができます
作ってみたばかりで、不具合等あるかもしれませんが、是非お試し下さい。
フィードバック頂ければ幸いです。
ダウンロード
※VBAマクロなので、Excel設定でマクロを許可して下さい
※Excel 2007で作成しています
※UTF-8対応のため、UTF-8ファイル作成 for VBAのライブラリを使わせて頂きました。作者様に感謝致します。
みなさん、本当にお待たせしました!!
音楽生活をより楽しくするための音楽試聴AndroidアプリケーションMusicFlyが満を持して本日バージョン2.1にアップデートしました!


今回のアップデートの目玉は
- 人気アーティスト、アルバムランキング機能
- 気まぐれアルバム検索機能
- 検索キーワード履歴
です。
他にも細かい修正や、機能追加など盛りだくさんの内容ですので
ぜひとも、あなた自身の目で、耳で、その違いを体感してください。
新バージョンのMusicFlyのダウンロードはこちら
弊社の人気サービスである音楽試聴AndroidアプリケーションMusicFlyが
AuのAndroidアプリ紹介サービスAuOneマーケットにおいて
月間ランキング
週間ランキング
に輝きました!!

多くの方に愛され、応援していただき
ありがとうございます。
もうじき待望のバージョン2.1をリリースしますので
ご期待ください。