ラベル Android の投稿を表示しています。 すべての投稿を表示
ラベル Android の投稿を表示しています。 すべての投稿を表示

2016年1月21日木曜日

[Android] In-app Billing v3を使ってライセンス購入を実装するLicenseManagerをアップデートしました

憂鬱なムックを助ける友の会: [Android] In-app Billing v3を使ってライセンス購入を実装する で紹介していたLicenseManagerクラスですが、onCreateでnewして、onResumeでisLicensePurchased()メソッドにて購入状態を判定するという作りにしていましたが、onCreateからonResumeが走るまでにIn-app Billing APIが結果を返しきる保証は何もないので、判定を誤るという可能性がありました。

そこで、そのバグ(そう、これはバグです!すみませんっ!!)を修正しましたのでご案内します(そして、コミットログ、ミスりました。。。恥ずかしい。。)

https://github.com/shinchit/LicenseManager

使い方はほぼ変わりません。ただ、newした段階でIn-app Billing APIが結果を返し済みであることを確認してから先の処理に進むように改修していますので、newの直後にisLicensePurchased()メソッドを使っても問題ありません。

技術的には、非同期処理の順番、完了待ちを保証するために、JDeferredというライブラリを利用しています。
そのため、appレベルのbuild.gradleのdependenciesに

 compile 'org.jdeferred:jdeferred-android-aar:1.2.4'

といった記述が必要です(バージョンは適宜調整してください。動作確認をとっているのは1.2.4です)。

JDeferredの細かい使い方については、公式、または次のページがわかりやすいです。

Java - Androidの非同期処理を綺麗に書けるjdeferredが便利! - Qiita

LicenseManagerでは、以下の記述でnewの中でIn-app Billing APIへの非同期リクエストが帰ってくるのを待ち合わせています。

ちなみに、ここではJavaのλ式(ラムダ式)を利用しています。が、別に使わなくても問題ないです^^
ただ、見てお分かりの通り、λ式を使うと型の迂遠な明示が省略できるので楽に読み書きでき、スッキリして見えます。

また、GitHub上のLicenseManagerでは、アプリのライセンスキーを暗号化せずにそのまま渡していますが、実際のリリースapkを作る際にはそれはオススメできません。ライセンスキーは暗号化して保持し、これを復号化してLisenceManagerに渡すようにするべきです。とはいえ、暗号化のseedはapk内に持つため、その気になれば簡単に復号化もできてしまうのですが。。。万全を期すなら、seedを外部のサーバ(Webサーバなど)において、SSLでそれを取得してというのが良いのでしょうが、、、そこまでやる必要もないかと(というか、それをやると実装によってはオフラインでアプリを使用できないシーンが出てくるし)。
この辺の、暗号化・復号化の話はまた別エントリーで取り上げます。

[Android] Android Studioでaarライブラリを取り込む方法

Android Studioでaarで提供されているライブラリをプロジェクトに取り込むには次のようにします。

まず、プロジェクトレベルのbuild.gradleに次のようにflatDirの記述を追加します。

flatDirのdirsのパスは任意のパスを指定できますが、ここでは簡便に使えるプロジェクトのapp/libs/を指定しています。

次に、appレベルのbuild.gradleに次のように取り込むaarファイルの情報を追記します。


ここまで行ったら、プロジェクトのapp/libs/ディレクトリに目的のaarファイル(例ではHogeHoge.aar)を設置します。

あとは、Android StudioでSyncProject(下図の赤枠部)を実行すれば無事にaarがプロジェクトに取り込まれて幸せになれます。

Sync Project with Gradle Filesボタン


参考:
 AndroidStudio - Android Studio でaarをローカルから読み込む方法 - Qiita

2015年11月4日水曜日

[Android] Recent Apps(アプリ履歴)にActivityを表示させない方法

非常にニッチなニーズなのですが、諸般の事情で実装する必要があったので備忘で書いておきます。

Recent Apps(アプリ履歴、タスク一覧ともいうのかな?)に対象のActivityを非表示にするには、対象Activityがフォアグラウンドになければ


にある通り、AndroidManifest.xmlにて対象Activityの<activity>に

android:excludeFromRecents="true"

を指定してあげれば非表示になります。

問題は、対象Activityがフォアグラウンドにある場合で、その場合は、下記のようにexcludeFromRecents以外に色々と設定してあげる必要があります。
(TargetActivityはご自身のActivity名に読み変えてください)。


正直、各設定の詳細な意味は深く理解していません(汗
おまじないに近いです。

次の記事を参考にしました。

Issue 53313 - android - Foreground service killed when receiving broadcast after acitivty swiped away in task list - Android Open Source Project - Issue Tracker - Google Project Hosting

2015/11/7追記:

もっと簡単で確実な方法がありました。onPause()でsetTheme(android.R.style.Theme_NoDisplay)すれば良いです。

protected void onPause() {
    setTheme(android.R.style.Theme_NoDisplay);
    super.onPause();
}



2015年7月7日火曜日

[Android] アクティビティの多重起動を防ぐ

Serviceを使ってマルチスレッドからActivityを呼び出す(startActivity())ことをやっていると、Activityが多重起動してしまいErrorが生じてしまうケースがあります。(スレッドセーフに作られているActivityならいいのですけどね)。

このケースの解決方法として、アクティビティの多重起動を防ぐという方法があります。やり方は簡単で、AndroidManifestで多重起動を防ぎたいアクティビティのactivityタグでandroid:launchMode="singleInstance"を指定するだけです。
記述例は次の通り。

参考:
 プログラムの多重起動と連続起動について - fの備忘録

2015年5月24日日曜日

[Android] In-app Billing v3を使ってライセンス購入を実装する

Androidアプリでアプリ内課金を行う場合、Google Play In-app Billingを使ってGoogle Playに決済を任せる設計が一般的&楽です。

アプリ内課金には、スポット課金(一度きりの購入)と定期購読(繰り返し自動課金)を使うことができ、スポット課金を利用するとアプリのライセンス購入を表現することができます。

最初は、無料でダウンロードしてもらって使ってみてもらい、気に入ったらライセンスを購入してもらって、加えていた制限(例えば利用期限だったり、機能制限だったり、広告非表示だったり、色々)を解除することが可能というわけです。

このアプリ内課金を実装するための手順は次の記事が参考になります。

Androidのアプリ内課金IABv2のサービス終了と新しいIABv3への移行方法 - Qiita

基本的には、挙げた記事の通り、環境を作って、Googleが提供しているサンプルを取り込んでゴチャゴチャやればOKなのですが、今後はシンプルにやりたいと思いましたので(=今回は初めててで結構苦戦しました)、ライセンス管理を行うユーティリティクラスをGoogleのサンプルをベースに作りましたのでGitHubで公開しておきます。ライセンスはMITです。

https://github.com/shinchit/LicenseManager

使い方は、次の通りです。



onActivityResultメソッドでは、特に購入処理の実行結果によってなんらかの処理を行う必要がなければ、シンプルにスーパークラスのonActivityResultに処理を転送すればOKです。

あと、実装以外にもライセンス購入の組み込みには色々と落とし穴もあるので、次の記事も必読です。

アプリ内課金の実機テストのワナ - GADGET FACTORY 雑記帳


2015年4月10日金曜日

[Android] strings.xmlに可変パラメータを埋め込む(sprintf的な)

strings.xmlに静的な文字列だけでなく、文字列の一部がプログラムによって動的に埋め込まれるような文字列を設定したい場合(つまりはよくある言語のsprintf的なことをしたい場合)は、次の例のようにします。


[Android] TextViewのtextにHTMLを使用する

TextViewのtextにHTMLを使用しようとしても、普通に行うとHTMLタグは効きません(文字列としてそのまま出力されます)。 HTMLタグを有効にするにはandroid.text.Html#fromHtmlを使います。


また、strings.xmlにHTMLを記述するためには、<、>、&、"をエスケープ表記する必要があります。先の文例で考えるなら、以下のようになります。

2015年4月7日火曜日

[Android] TextViewを疑似hiddenとして使う

一覧表示などで、一覧中のどの行をタップしたか取得したいケースはままあるかと思います。その場合、HTMLでは<input type="hidden">に隠しパラメータ(この場合は行番号)をもたせておくという方法がよく採用されますが、これと同じようなことをAndroidアプリで行いたい時にどうするか。一つの方法は非表示にしたTextViewを使うことです。

ポイントはandroid:visibility="gone"の指定です。この指定によって、TextViewは単に非表示になるだけでなく、レイアウト上、あたかも存在しないかのように扱われます。しかし、値を保持する箱としては使えますので、疑似hiddenのように扱うことができます。

このTextViewへの値の取得、設定は下記のようになります(一例)。


[Android] ImageViewを左右の両端に配置する方法

LinearLayoutなどを使って普通にImageView(やButtonなど)を二つ続けて記述すると、layout_gravity属性にそれぞれright、leftを指定しても、左詰めで表示されてしまいます。GridLayoutやTableLayoutを使ってセルを定義して左右の端に表示する方法もありますが、XMLの記述が複雑になりますし、端末の画面サイズによってはImageViewが見えなくなる現象が起きたりします。また、Layoutの上にViewを配置することもLinearLayoutの方がシンプルに実現できます(LinearLayoutのbackgroundに画像をセットして、<LinearLayout>〜</LinearLayout>にViewを置くことで、画像の上にViewを配置できます)。

それで、LinearLayoutで左右の両端にImageViewを表示する方法ですが、空(空文字)のTextViewを二つのImageViewの間に挟むことで実現できます。
ポイントはgravity="center"を持つTextViewが二つのImageViewの間にあって、そのlayout_weightがImageView達のlayout_viewより高く設定されていることです。この設定によって、TextViewが中心に鎮座して最大限に幅をきかせようとするので、結果として二つのImageViewが左右両端に(TextViewにおいやられて)表示されることになります。

2015年4月1日水曜日

[iOS] [Android] [Hybrid] [Monaka] Monakaを触ってみました

Monaka を使ってHybridアプリの実装を試してみています。
チュートリアルが充実していて(しかも日本語)開発手順(速習編)をなぞることで、プロジェクトの作り方から実機でのテスト、配布まで1時間ぐらいで覚えられました。

触ってみた感触でのメリットは、

・IDEがクラウドで提供されていること
・ドキュメント(しかも日本語)が充実していること
・(当然ですが)ハイブリッドアプリが作れる
・デバッグ用のアプリが提供されており、実機でシームレスにテストできる
・WebViewでほぼ完結するアプリでJavaScriptが書けるなら、学習コストはかなり低い

というところです。

逆にWebViewベース中心ではなく、ネィティブアプリの機能をガリガリ使うなら第一選択にはならないかもしれません。この辺りはどこまでネィティブ機能を使えるのか調査中なので、推測にすぎませんが。

スマホ、タブレット端末向けサイトを構築する、という要件にはMonakaはとてもマッチすると思います。

2015年3月28日土曜日

[Android] LayoutInflaterを使って他のアクティビティのViewにアクセスする

LayoutInflaterを使うことで他のアクティビティのViewにアクセスできます(もちろん自分自身のActivity内で複数のレイアウト(XML)を使うこともできます)。

MainActivityとSubActivityの二つのアクティビティがあるとします。ここでMainActivityが使用するレイアウト(XML)をR.layout.main.xml、SubActivityで使用するレイアウト(XML)をR.layout.sub.xmlとします。それぞれのXMLを示します。
main.xml
sub.xml
ここで、SubActivityからR.layout.main.xmlのTextView(R.id.main)にアクセスするにはLayoutInflaterを使って次のようにします。
この方法を活用すると、この例のように他のアクティビティのViewにアクセスするだけでなく、ボタン押下のタイミングで異なるレイアウトを切り替えたり、ヘッダ、フッタのような共通レイアウトの使用を行うことができます。

2015年3月27日金曜日

[Android] AdMobを実装して広告を表示する

AdMob(https://apps.admob.com/)のアカウント登録、アプリ登録、広告定義は終えているものとします。

また、アプリのプロジェクトにgoogle-play-servicesが既に組み込まれているものとします。

ここまでの詳しい手順は、
がとても参考になります。

ここまでの条件が整っているという過程のもと、Activityに広告を表示するには対象ActivityのonCreate内で以下のようにします。

テストモードでの広告表示に必要な、ハッシュ化された端末IDの取得は
 [Android] AdMob テストで使う、デバイスIDを取得
のエントリーに書かれている方法を使うと、デバイス切り替えごとにIDを書き換えずに済んで素敵です。

2015年3月24日火曜日

[Android] ImageViewに設定されている画像を切り替える

状態を二つだけ持つ(画像の)ボタンであればToggleButtonを使えばよいのですが、3つ以上の状態を持ち、さらにその時に設定されている画像の状態に応じて処理や画像を切り替える場合、ToggleButtonでは対応できないので、次のようにします。

Preferencesを使ってステータス管理する方法もありますが、この方法の方が状態の情報が二重化しませんし、直感的なのでより良いと私は考えます。

2015年3月14日土曜日

[Android] [Java] 親クラスのクラス名を得る

extendsで親クラス名を書いていますので、それを再び書けばいいのですが、DRYじゃなくなるので以下の書き方を使っています。

2015年3月12日木曜日

[Android] R.string.*から文字列(String)を取得する

XML内では@string/somekeyのように書くことでres/values/strings.xmlに定義した文字列(下例参照)を得られます。



しかし、Javaコードの中では単純にR.string.somekeyはint値であるため、そのままでは指定した文字列を得られません。getResources().getString(int)を使います。




2015年2月20日金曜日

[Android] apkファイルをインストールする方法

もともと行いたかったことは、家のiMacと同じ環境(Android Studio)をMacbook Airの環境にプロジェクト毎コピー(エクスポート&インポート)したかったのですが、探してもAndroid Studioにプロジェクトのインポートはあってもエクスポートがありませんでした。

そこで、apkファイルを作成して、それをインストールすればプロジェクトがインポートされるのではないか?と勝手に決めつけてアレコレやってみました。結果、プロジェクトのインポートはapkファイルでは出来ないということが解りました^^;

ただ、エミュレーターや実機にapkをインストールする、つまりアプリケーションをインストールする方法がわかりましたので、その手順を以下に書きます。

1. adbにパスを通す


2. Android Studioでエミュレーターを立ち上げる、または、実機をUSB(データ伝送できるUSBであることに注意!!)でつないで、adb installする



2015年2月17日火曜日

[Android] ホーム画面に遷移する方法

特定のActivityにではなく、ホーム画面に遷移するには以下のようにします。
通常、Activityへの遷移は二つの引数(コンテキストと起動Activityのclass属性)を取るコンストラクタを使いますが、ホーム画面に遷移する場合はIntent.ACTION_MAINのみ与えるコンストラクタを使います。

参考
 HOMEボタン押下と同じ処理をするには

[Android] ServiceからActivityを起動する

ServiceやReceiverからActivityを普通にIntentで起動しようとしてもエラーになります。起動するにはIntentにFLAG_ACTIVITY_NEW_TASKフラグを設定します。

例えば、Serviceで定期的に状態を監視し、ある条件を満たした場合にActivityを表示する、などに使えます。Intentを使ったパラメータの授受も通常通り行えます。

2015年2月12日木曜日

[Android] 遷移先Activityから遷移元Activityに戻る方法

[Android] 他の画面(Activity)にパラメータを渡して遷移する にてIntentを使って画面(Activity)を遷移する方法を示しました。この場合に、遷移先Activityから遷移元Activityに戻るにはfinishメソッドを使います。

Intentを使って再遷移する方法とは異なり、遷移元Activityのクラス名を遷移先Activityが知る必要がないので、finishを使う方がDRY(Don't Repeat Yourself)でおすすめです。

2015年2月10日火曜日

[Android] 他の画面(Activity)にパラメータを渡して遷移する

android.content.Intentを使います。

まず、画面遷移(他のActivity)に遷移するなら次の通りです。

この際に、パラメータ(任意のオブジェクトも可)を渡すならintent.putExtraを使います。
putExtraの第一引数はパラメータのキーで、第二 引数が渡したいパラメータそのものです。
遷移先Activityでのパラメータの受け取りも含めて例を示します。