アプリでSMSを受信したい

2011年6月11日

携帯へ何かを通知したい場合、日本のようにi-modeメールでプッシュ配信できない海外では、SMSを使うのが主流。サーバーからアプリに何かの情報を配信する場合も、この仕組みをつかうのが一番簡単だと思う。

★AndroidのSMSに関する資料

上に紹介したAPI Demoをビルドして検証しようとしたところ、なぜかSMSのデモがメニューからなくなっていた。調べてみると、自分のAndroid(Experia X10 mini: Android version 2.1 update)にあわせて設定したビルドターゲット、つまりAPI Level 7(=Version2.1 update)のAPI DemoにはSMS関連のソースが無かった(Level8と9にはある)。ビルドターゲットをAPI Level8 でAPI Demoのプロジェクトを作り直しすと、SMS関連のデモも動いた。

エミュレータにSMSを送るには、Eclipseで[Window]-[Open Perspective]-[DDMS]を開き、Emulator Controlから送信。

SMSを受信すると、メッセージを表示するウィンドウが現れ、さらにメッセージを読み上げる。SMSを受信する設定になっている間は、API Demo の画面を閉じても、SMSを受信するとメッセージを表示するウィンドウは現れる。

しかしSDKのリファレンスによると、SMS関連のクラスはAPI Level7でも使えるはずだ。API Level 8のAPI DemoのソースからSMS関連のソースをコピーしてビルドターゲットをAPI Level 7にしてビルドしてみた。

新規プロジェクトを作成し、SmsMessageReceiver.java と SmsReceivedDialog.java はそのままコピーしてPackage名だけを変更。プロジェクトのActivityクラスには、SmsMessageDemo.java の中身をそっくりコピー。res/values/strings.xml には、関連する文字列をコピー。res/layout/sms_demo.xml はそのままコピーしただけではビルドできなかったが、プロパティ layout_widthとlayout_heightの値 “match_parent” を “fill_parent” に置き換えてビルドできた。

・・・で、動かしてみるが、SMSを送っても反応しない。SmsMessageReceiver にブレークポイントを張って動かしてみたが、最初から最後まで止まらない。よくソースを見返してみると、SmsMessageReceiver を BroadcastReceiverとして追加するコードがない・・・。API Demo の元のソースをみてもない。しかし、上で紹介した http://www.androidcompetencycenter.com の記事を見て、Manufest.xmlで Receiver として設定する必要があることがわかった。API Demo の元のソースにもあったので、そこからコピー。さらに、元の Manufest.xml には SMSの機能に関する uses-permission も設定されていたので、それもコピー。これで SMS に反応するようになった。

しかし、SMS を受信してすぐに落ちてしまう・・・。ログを見ると、権限が足りなくてExceptionが発生している。SMS 関連の uses-permission は全てつけたはずだが・・・?デバッガで見てみると、SMS を受信した後で、電話帳から発信元番号の主を検索する処理が入っていて、ここで落ちていた。なるほど!電話帳のアクセス件が必要だったわけだ。確かに元の Manufest.xml にはあったので、それをコピーして追加。これで正常に動くようになった。SMS の受信だけでなく、電話帳の検索方法まで紹介してくれていた。なんて親切なサンプルコードなんだ!(>_<)

ちなみにiPhoneでは、SMSの送信はできるが受信はできないらしい。アプリにプッシュ式で通知する仕組みとしては、Local and Push Notification というのがあるようだが、ハードルが高そうなので、今は止めておく。

★iPhoneのSMSとLocal and Push Notification に関する資料

ゴルフのスコアカウンター(iPhone版)

2011年5月28日

ゴルフのスコアカウンターのiPhone版。

ソース

●画面のレイアウト

layout

レイアウト

Window baseアプリケーションとして作成。図のように配置した。PARの値を選択するのにドロップダウンリストを使いたかったが、ドロップダウンリストがなかった。仕方なくSegmented controlを使用した。

●クラス構成

xibファイルのFileOwnerはAppDelegateなので、イベントハンドラはここに書くこともできたが、今回はあえてGUIイベントハンドラとして、Controllerという名前のNSObjectの派生クラスを作成した。同時にxibファイルにもObjectを追加し、Custom Class にControllerクラスを設定して連携させ、AppDelegateにOutletとして追加することでインスタンス化する。(一方、Viewを使った場合はView毎にxibファイルを作成するので、UIViewControllerの派生クラスはxibファイルのFileOwnerに指定する。よって、ControllerのObjectを別途xibに追加しなくてよい。アプリ初期化時にinitWithNibNameにxibファイル名を指定して呼び出すことで、xibを読み込んでインスタンス化する。)

●データの初期化

スコアのデータは2次元配列に保持する。Controllerを分けたので、モデルも別にしようかとは思ったが、面倒なのでControllerに持たせた。パーの値は4を初期値として設定する。この初期化処理は、AppDelegateのdidFinishLaunchingWithOptionsから呼び出す。

●イベント処理

前述のControllerクラスに各ボタンが操作された際のActionを定義し、xibで各ボタンのイベントと関連づける。

●課題

ドロップダウンリストの実装方法・・・。リストから選択させるときは何を使うのか?iPhoneを持っていないのでよくわからないが、買うと高いし・・・。サンプルなどをよく調べる必要がある。

ゴルフのスコアカウンター(Android版)

2011年4月30日

ゴルフのスコアをカウントするための、簡単なアプリを作成した。(私のようにダブルパー以上を普通に叩く人は、打数を数えるのが大変なので、こんなのが必要!)各ホールの打数を記録するとともに、トータルスコアとPAR数を引いたオーバーの値も出すようにする。

ソース

●画面のレイアウト

layout.xml

レイアウト

一番底がLinearLayoutで、上からホール数表示エリア、PAR表示エリア、スコア表示エリア、トータルスコア表示エリアとした。
ホール数表示エリア内をRelativeLayoutにしてホール数を増減するボタンを両端に、ホール数表示のラベル(TextView)を真ん中に配置した。
PAR表示エリアは、PAR数を選択するSpinnerのみ。
スコア表示エリアは、これもRelativeLayoutにしてスコアを増減するボタンを両端に、真ん中をさらにLinearLayoutにして上にこのホールのスコア、下にPARを引いた値を表示。
トータルスコア表示エリアはラベル(TextView)のみである。

●クラス構成

Activity の派生クラスのGolfscntという名前のクラスのみ。このクラスのonCreateメソッド内で、各コントロールのイベントハンドラを一時クラスとして実装している。

●課題

PARを選択するspinnerの字を他のにあわせて大きくしたいのだが、textSizeを変えても大きくならなかった。

課題という訳ではないが、実際に使ってみたとことろ・・・明るい野外では液晶が見にくくて、結局ほとんど使えなかった。残念・・・orz

ダウンロードはこちら

Cocoa Application Tutorial の Converterアプリを iPhone に移植

2011年4月9日

Cocoa Application Tutorial (下)の Converterアプリを iPhone に移植してみた。

CocoaTutrial

CocoaTutrial

プロジェクトの選択

NewProjectWindowBased

NewProjectWindowBased

プロジェクトの新規作成では Window-based Application を選択。
このあとは、Cocoa Application Tutorial の指示通りにすすめればOK。(ただし、コントロールのクラス名はNSTextField → UITextField という要領で置き換える。)

変更すべき点

しかし、Controllerの定義と実装には、NSTextField と UITextField の違いにより若干変更が必要。

【ConverterController.h】
★NSTextField を UITextField に置き換える。

@interface ConverterController : NSObject {
	IBOutlet UITextField *amountField;
	IBOutlet UITextField *dollarField;
	IBOutlet UITextField *rateField;
	Converter *converter;
}
- (IBAction)convert:(id)sender;
@end

【ConverterController.m】
★NSTextField にはあるが UITextField にはないメソッドを書き換える。

@implementation ConverterController
- (IBAction)convert:(id)sender {
    float amount;
    converter = [[Converter alloc]init]; 

//    [converter setSourceCurrencyAmount:[dollarField floatValue]];
// UITextField には floatValue がない
    [converter setSourceCurrencyAmount: [dollarField.text floatValue]]; 	

//    [converter setRate:[rateField floatValue]];
// UITextField には floatValue がない
    [converter setRate: [rateField.text floatValue]]; 	

    amount =   [converter convertCurrency];

//    [amountField setFloatValue:amount];
// UITextField には floatValue がない
    [amountField setText: [[NSNumber numberWithFloat: amount] stringValue]]; 

//    [rateField selectText:self];
// UITextField には selectText がない。
// 書き換えができなかったので、保留。

// iOS にはガベージコレクタがないので、リリースする必要がある。
	[converter release];
}
@end


また、数値の入力フィールドについては、キーボードを Number&Punctuation に設定した方が便利。


シミュレーターでの実行結果

iPhoneSDKのサンプルMoveMeをAndroidに移植

2011年3月6日

iPhoneSDKのサンプルMoveMeをAndroidに移植してみた。ソースはこちら

左がオリジナル(iPhone版)、右が移植したもの。

(ならべて見ると・・・大きさが違い過ぎだが・・・気にしない・・・ )

MoveMeというプログラムは、次のような簡単なプログラムである。

  • 最初に画面中央にメッセージ(短い挨拶文)が書かれたボタンが表示される。
  • ボタンをタッチすると少し膨らみ、ボタンの中心はタッチされた位置に移動する。
  • ボタンはドラッグして移動され、指を離すと中央に戻る。中央に戻ったとき、勢いでボタンがはねるような動きをする。
  • ボタン以外の部分をダブルクリックすると、メッセージの言語が変わる。

Viewの構成

iPhone版ではメインの親であるMoveMeView上のタッチされた位置に、子であるPlacardView(ボタン)を表示する。PlacardViewは親画面内の座標で位置指定される。Androidで小画面(コントロールも含む)の位置指定はLayoutManagerに依存する。LayoutManagerもViewを継承するので、これが親画面といえる。座標で位置指定するにはLayoutManagerとしてAbsoluteLayoutを使用する必要があるが、実はこのAbsoluteLayoutの使用は推奨されていない。これはAndroid(だけでなく一般的なJavaプログラムにもいえることだが)ではデバイスにより画面サイズが異なるため、位置を座標で指定すると画面からはみ出たり、逆に小さ過ぎたりする可能性があるため。一般にLayoutManagerは親画面に対する小画面の相対位置を指定し、デバイスの画面サイズにあわせて、小画面やコントロールを自動的に最適な場所に配置する。ただしこのプログラムでは、小画面は画面のタッチで位置指定されるので、画面サイズの影響を気にする必要はなく、AbsoluteLayoutでも問題なかった。

クラスの構成

iPhone版で定義されたClassと、Android版のClassの対応は以下のようになった。

  • MoveMeAppDelegate → なし(Delegateの仕組みがない)
  • MoveMeView(メインの画面) → MoveMe内で使用されるAbsoluteLayoutクラス。
  • PlacardView(ボタン) → PlacardView

Animationの使用

ボタンを最初にクリックした際にボタンがふくらむ動作と、ドラッグされたボタンから指を離すと中心に戻り、反動で少し揺れる動作はアニメーションを使用した。SDKのサンプルではXMLファイルで定義するアニメーションの例が多いが、今回はアニメーションの位置が動的に変わるため、XMLだけでなく、プログラムによる定義も使用した。

↓↓↓Animation定義のコード↓↓↓

	//animate moving to center
	final long DURATION_ANIM1 = 300;
	TranslateAnimation move_center = new TranslateAnimation(
			TranslateAnimation.ABSOLUTE, x - mCenter.x,
			TranslateAnimation.RELATIVE_TO_SELF, 0,
			TranslateAnimation.ABSOLUTE, y - mCenter.y,
			TranslateAnimation.RELATIVE_TO_SELF, 0);
	move_center.setDuration(DURATION_ANIM1);
	move_center.setStartTime(Animation.START_ON_FIRST_FRAME);
	move_center.setInterpolator(new LinearInterpolator());
	//animate bouncing
	TranslateAnimation bounce = new TranslateAnimation(
			(float)0,
			(float)(mCenter.x - (mPtEnd.x + WIDTH/2))/20,
			(float)0,
			(float)(mCenter.y - (mPtEnd.y + HEIGHT/2))/20);
	bounce.setDuration(200);
	bounce.setStartTime(Animation.START_ON_FIRST_FRAME);
	bounce.setStartOffset(DURATION_ANIM1);
	bounce.setInterpolator(new CycleInterpolator((float) 2.75));
	//AnimationSet consist of above two animation
	AnimationSet go_center_bounce = new AnimationSet(false);
	go_center_bounce.addAnimation(move_center);
	go_center_bounce.addAnimation(bounce);
	this.setAnimation(go_center_bounce);
	go_center_bounce.startNow();

イベントハンドラ

iPhone版では親画面であるMoveMeViewにイベントハンドラが定義されているが、Android版では、親画面となるAbsoluteLayoutにListenerを追加し、そのListener内にイベントハンドラを定義することになる。1つよくわからないのが、ダブルクリックの判定方法で、今回は前回クリックされてから何ms以内に次のクリックがあればダブルクリックと判定している。あまりスマートでない感じがするので、もっといい判定方法を調べなければ。

AbsoluteLayoutによるボタンの位置指定

AbsoluteLayoutのLayoutParamsが位置の属性を持つ。ということは、このLayoutParamsの参照を保持しておき、属性を変更することで位置を変更できるかと思いきや、位置を指定するたびにAbsoluteLayoutのsetLayoutParams()を呼び出す必要があった。

まとめ

今回のサンプルは非常に簡単だったので、アニメーションの使用を除けば、一般的なJavaプログラムとそれほど変わらず、Androidだからということで特別に意識するところはなかった。Javaが使えるので、iPhoneよりは敷居が低そうだ。

Android SDK のHello, World! ・・・あれ?動かない・・・

2011年1月29日

Android SDKのTutrialを試してみた。

http://developer.android.com/resources/tutorials/hello-world.html

指示通りにプロジェクトを作成し、ソースを編集して、実行。

“Hello, World!”って文字を表示するだけだから、まず大丈夫だと思っていたら・・・

あれ?? 動かない・・・と思っていたら

画面が変わった! やっと起動したらしい。でも”Hello,World!”は?

焦っていろいろボタンを押してみると

“MENU” ボタンで出てきた!

Hello world!

2011年1月15日

Welcome to WordPress.com. This is your first post. Edit or delete it and start blogging!