ランタイムパーミッションの対応をするとActivityがマッチョになるのなんとかならんかな

Android6.0からアプリのインストール時ではなく、パーミッションを必要となる操作を行う前に許可を求める形式になった。これ自体はとてもよいこと。インストール時にやたら権限を要求するアプリがなんだか怖くてインストールすらしなかったのが、これのおかげでとりあえず試して見れるようになったのはとてもよい。

Read full post gblog_arrow_right

Crashlyticsのクラッシュレポートをdebugビルドでは行わないようにする

新しいアプリを作るときにしかやらないので、いつもやり方を忘れてしまうCrashlyticsのレポート設定のメモ。 デバッグビルドでまでクラッシュレポートが報告されてしまうと、通知がうっとうしいだけですし、手元でスタックトレースが読めるわけですから完全に無駄です。必要なのは基本的にはリリースビルドだけでしょうから、開発中は無効にしてしまうのが便利です。 やることは下記のページのとおりです。 https://docs.fabric.io/android/crashlytics/build-tools.html?gradle#build-tools まずはレポートを無効にしたいbuildTypeにext.enableCrashlytics = falseを追加します。 この設定はGradleのビルド時に、Crashlyticsで使うIDなんかを生成する処理を行わないようにするもののようです。レポート送信を止めるわけではないので、これを追加しただけでは下記のようなエラーが出てしまいます。 This app relies on Crashlytics. Please sign up for access at https://fabric.io/sign_up, install an Android build tool and ask a team member to invite you to this app's organization. 開発時にレポート送信自体を止めるためには、アプリ実行時にCrashlytics自体が動かないようにする必要があります。そのためには、Crashlyticsの初期化を行う部分で、下記のように初期化を行います。 Crashlytics crashlyticsKit = new Crashlytics.Builder() .core(new CrashlyticsCore.Builder() .disabled(BuildConfig.DEBUG).build()) .build(); Fabric.with(this, crashlyticsKit); ちなみにdebuggableがfalseなんだけどCrashlyticsのレポートを無効化したい、なんていう場合には、.disabled(BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("test"))のようにしてやればOK。 レポートが送信されないことの確認 アプリの任意の場所でthrow new RuntimeException("Crashlytics report test");と例外を投げてみればOK。 ただし例外を投げる場所に注意が必要です。Crashlyticsの初期化が終わっていないと、そもそもレポートが送信できません。Applicationクラスの外か、ActivityのonCreateの外で例外を投げるようにしないとテストにならないので注意しましょう。 https://docs.fabric.io/android/crashlytics/introduction.html

CapabilityAPIを使う場合、アプリのパッケージ名に注意

Android Wearのアプリを作成する際には、パッケージ名をスマホ側と同じにしなければなりません。 新規プロジェクトで初めからWear用のアプリも含めて開発する際は関係ない話です。Android Studioの新規プロジェクトウィザードでターゲットにWearを追加するだけなので、両者のパッケージ名を別のものにしようと思ってもできません。 気をつけなければならないのは、スマホ用のアプリを作成していて、途中からWear用のモジュールを追加する場合です。「Wear用のモジュールだからパッケージ名変えたほうがいいかな」なんて気を利かせると逆にハマります(私のように)。 (ちなみにここで言っているパッケージ名は、アプリのパッケージ名のことです) 開発時はWear用のモジュールを実行、スマホ用のモジュールを実行という感じでアプリをインストールして実行できるので問題に気づきにくいのですが、Wearとスマホで通信を行おうとした際にハマります。 具体的にはCapability APIを使って通信可能なノードを取得する際に、パッケージ名が違うとそのノードが取得できません。 https://stackoverflow.com/questions/35136881/cant-detect-node-using-the-capability-api Capability APIはWearからの要求に応答可能なデバイスを探すための仕組みです。例えば自分で 「say_helloという要求を行う」と定義しておけば、Wearからメッセージを送信する際にsay_helloが定義されているデバイスだけを、Capability APIを使うことによって取得することが出来るのです。しかし、それはパッケージ名が同じアプリであればの話です。 ちなみにNode APIを使えばパッケージ名が異なっていようが関係なく、ペアリングされているノードが取得できます。パッケージ名が異なると接続されているノードが取得できないのはCapability APIを使った場合の話のようです。 Wearアプリを作成する場合、パッケージ名を変えることは基本的にはないと思いますが、Wearのパッケージ名とスマホのパッケージ名を異なるものにすると弊害があるぞというお話でした。特に後からWear用のパッケージを追加するときには気をつけましょう。

Bluetooth経由でデバッグする

Android WearデバイスをBluetooth経由でデバッグする方法について。 Android WearもUSB経由でパソコンに接続してデバッグする方が何かと便利です。ですが、USB経由で接続しようと思うと、Wearデバイスに直接USBケーブルをつなぐタイプのものなら問題無いでしょうが、クレードル経由で接続するタイプの製品だと腕につけた状態でデバッグできません。 そんなときはBluetooth経由でデバッグすると便利です。 https://developer.android.com/training/wearables/apps/bt-debugging.html Android Wearでの事前準備 Bluetooth経由でのデバッグを有効化しておく必要があります。 まず設定→端末情報→ビルド番号を7回タップして開発者オプションを有効にします。 すると開発者オプションを選択できるようになるので、そこからADBデバッグとBluetooth経由でデバッグを有効にします。 以上でWear側の事前準備はOK。 スマホ側での事前準備 Android Wearとペアリングしているスマホ側でもBluetooth経由のデバッグを有効化してやる必要があります。 Android Wear companion app(日本語だと単にAndroid Wear)を実行します。Android Wearとのペアリングしたりするアプリです。 使いたいAndroid Wearデバイスとのペアリングした状態で、Appbarにある歯車アイコンを押します。 すると設定画面が開くので、その一番下にあるBluetooth経由のデバッグを有効にしてやります。 ホスト:未接続、ターゲット:接続済みとなっていると思います。 それができたら次のステップ。 パソコンからターミナルで操作 以下のコマンドを実行。 adb forward tcp:4444 localabstract:/adb-hub adb connect localhost:4444 adb connect localhost:4444でConnection Refuesedとなってしまう場合、localhostの部分を127.0.0.1とすれば接続できると思います。 接続できればスマホで「ホスト:未接続」となっていた部分が「ホスト:接続済み」となると思います。 そうすればAndroid StudioからAndroid Wearデバイスが見えるようになっていると思います。 切断 adb disconnect 127.0.0.1:4444 adb forward —remove tcp:4444 ちなみにポートフォワーディングしているかどうかを確認するにはadb forward —listで確認可能。 もっとも、スマホのUSBケーブルを抜くとそのままBluetooth接続も解除されるので、わざわざ上記コマンドを叩いて切断する必要はまったくありません。 注意点 Bluetooth経由のデバッグでも、デバッガでブレークポイントを設定したりステップ実行したりすることができます。ただし、USB経由でのデバッグと比較すると格段に遅いです。 アプリのインストールもBluetooth経由で可能ですが、やっぱりUSBで繋いだ時と比べると遅いです。 ケーブルレスでデバッグできるのは便利なのですが、可能であればUSBで実機をつないでデバッグした方が開発サイクルを早く回すことが出来ると思います。 Bluetooth経由のデバッグは、Wearを腕にはめた状態でないと出来ない動作の確認(センサーを使った動作のデバッグ)などに限定して使ったほうがいいと思います。 ちなみにBluetooth経由のデバッグを有効にした状態で、WearをUSBで直接パソコンにもつないでおくと、WearデバイスはBluetoothで接続したものとUSBで接続したもの2つが見える状態になります。

久しぶりにAndroid Wearの電源を入れた

私はLG G watch Rを持っていたのだけれども、長いこと使っていなかった。普段腕時計をしないし、するにしても薄くて軽いやつをずっと使っていたので、スマートウォッチの大きさが我慢できず、そのうちつけるのをやめた。

そんな放置していたスマートウォッチを久しぶりに使ってみた。

Read full post gblog_arrow_right

暗号化について勉強中

Androidでユーザデータを暗号化して保護するにはどうしたらいいのでしょうか。 これまで「暗号化のやり方がよくわからないから、機密情報を保存しないようにしよう」と避けてきたのですが、それにも限界があるのかなぁと思って、手を広げてみる気になったのです。 まあ本当の出発点は、ユーザデータの保護ではなく、アプリで扱うデータを秘匿するにはどうしたらいいのだろうだったんですけれど・・・。 例えば、Twitterクライアントを作るとして、そのAPIキーをどうやって秘匿するのかということです。 Androidでこの手のAPIキーを扱う場合、サンプルではJavaのコードに直接書いてありますが、実際に自分でリリースするアプリでもそのままでいいのかという話です。 AndroidではAPKを簡単に抜き出して、しかも簡単にソースコードを確認することもできます。ProGuardで難読化をしても、Javaのコードに埋め込んだ文字列はそのままです。 String api_key = "hogehoge";のapi_keyの部分はProGuardによってaとか意味のない文字に書き換わりますが、”hogehoge”の部分は書き換わりません。(書き換わったらプログラムの動作が変わってしまうので当たり前です) つまり、やろうと思えばAPIキーは見放題ということになります。 だからここの部分、どうするのがセオリーなんだろうってのから始まって、暗号化すれば秘匿できるのかなと思ってみたのです。 多分、ユーザに見せたくないデータはアプリで保持しないのが正解であって、暗号化は関係ないと思いますが、それでも今まで放置していた暗号化に関して勉強するいい機会ではあるのでそのまま続けております。 どう勉強してるのかって話ですが、https://developer.android.com/training/articles/keystore.htmlを見たり、Android Studioのimport Sampleで取り込めるGoogleのサンプルコードを使ったりしてます。 実際に手を動かしてみて初めて知ったのですが、同じ文字列を同じ暗号化鍵で暗号化しても、得られるバイト列が毎回異なることに驚きました。”abc”を同じ暗号化鍵を使って暗号化したら、毎回123になるというイメージを持っていたものですから、なんで毎回異なるバイト配列になるのか不思議です。しかも異なるバイト配列になるのに、復号化したらちゃんと”abc”に戻るのですからなお不思議です。 これは一体どういう仕組なのか。そもそも暗号化の仕組みを理解せずに使うのは逆に危険なんじゃないのかと思い始め、今度はこんな本を読み始めました。 暗号技術入門 第3版 秘密の国のアリス posted with ヨメレバ 結城 浩 SBクリエイティブ 2015-08-26 Amazon Kindle 紀伊國屋書店 まあまだ読んでいる最中なんですけど面白いです。 本書には 弱い暗号は暗号化しないより危険である という考え方が序盤で紹介されています。仕組みを理解せずに暗号化するのもまた良くないと言えるのではないでしょうか。 安定の結城先生なので非常に分かりやすく、楽しく読めそうです。 それにしても、初めはAPIキーを秘匿することがきっかけだったのに、我ながらよく脱線してきたものだなぁと思います。

Contextの使い分けについて私が辿った変遷

Application Contextを渡してはいけないという記事を読みました。 https://ytrino.hatenablog.com/entry/2016/05/26/033936 この記事を読んで改めて自分のContextに対する認識があまいことを実感したので、思ったことをまとめてみようと思います。 趣旨は「僕はContextに対してこういうふうに思ってるんだけど、違う・違わないが自信持ててないから誰か突っ込んでくれ」です。たぶんそんなに間違ってないと思うんですけど、相談できるような相手がいないんだ、察しておくれ。 「私もそういう認識です」と言ってもらえれば自信になるし、違う部分があれば指摘をもらって学びの機会になり私のためになります。また、こういう変遷を経て学んできたという情報が初学者の役に立てばなぁなんて思ってもいます。 私のAndroidレベルは初学者というわけでもないですが、Contextにまつわる話を聞くと理解が曖昧でモヤモヤするレベルです。上記記事に倣えばAndroid2級でしょうか。 私は最近でこそライフサイクル考えてContextを使い分けるようになりましたが、ちょっと前まで「困ったらApplication Context渡しとけば問題ない」という考えの人でした。前までというか、今もそういう部分があるんですけどね。だからこそ「Application Contextを渡してはいけない」というのを見て不安になってしまいました。 渡してはいけないの意味 Application Contextを渡してはいけないというのは、どういう意味なのでしょうか。 アプリがクラッシュするから渡してはいけない 表示がおかしくなるから渡してはいけない 渡しても動作上は問題ないが、コードの見た目上・意味的に美しくないので渡してはいけない 実はApplication Contextをなるべく使おうというのも、Application Contextを渡してはいけないというのも、あるコンテキストにおいては間違ってないんじゃないかなと思います。それぞれ違うコンテキストで話しているので、そこを混同すると混乱してしまいます。 前者は「メモリリークを回避する」という文脈での話で、Activityのリークを防ぐにはApplication Contextを使えばいいのは正しい(はず)です。 一方後者はthemeの適用の観点での話で、Application Contextでは意図した動きにならない・変にハマることがあるからApplication Contextを安易に使ってはいけないという話で、これはこれで正しいわけです。 どっちも正しいのですが、残念ながらコードを書いていてContextを要求された時に、私たちは何らかのContextを渡さないと先に勧めません。何を渡せばいいかは「ケースバイケースなんで一概にどれを使えとは言えない」んで、Contextの要求に対しては、それぞれ適切なContextを渡す必要があります。 ではどのようにしたら、何を使うのが適切かを判断できるのでしょうか。ライフサイクルを考えろということでしょうか。そのライフサイクルはどうやって判断するんでしょうか。 私はその判断を、今はソースコードを読むことで行っています。Contextを要求するメソッドが、クラスが、いったい渡されたContextをどのように利用しているのか。それをもって何を渡すか考えています。 Contextについて私の辿った道 Androidを学び始めた当初は、Contextなんて意識していませんでした。本やサンプルコードの写経する分には意識しないですみますから。 しかし写経から脱し、自分でコードを書き始めるとそうもいきません。こういう処理を実装したいな→このメソッド使えばなんとかなりそう→Contextが必要らしい。はたとキーを打つ手が止まります。 そのメソッドを使うにはContextを渡すしかない。渡さないと先に進まない。とりあえずthisって書いたら動いた。よし、これで先へ進める。なんていうのが、Androidを学び始めた人が辿る道ではないでしょうか。私はそうでした。 学び始めの頃はActivityからなんかすることが多いので、this、すなわちActivityを渡していればとりあえずは動いてくれました。私はそうして「ああ、ContextっていうのはActivityを渡せばいいのだな」と認識するようになりました。 しかしActivity Contextを渡してしまうとメモリリークが発生するぞという話を耳にします。そこで登場するのがApplication Context。getApplicationContext()を使えばメモリリーク対策になるという話を聞いて、「ああ、じゃあとりあえずApplication Contextを渡しておけば問題ないのか」となりました。 しかし今度はApplication Contextを渡すと想定通りにViewが表示されないことがあるという。無思考にApplication Contextを渡すのもどうやらダメらしい。 一周回ってきてしまいました。もう一体どうしろと。このメソッドContext要求してくるのに僕は一体何を渡せばいいんだ。 私のContextとのつきあい方 そんな私が多少なりとも指針を持てるようになったのは、一言で言ってしまえば慣れてきたからなんだと思います。 とりあえずコード書いて、動かしてみて。それを繰り返すうちに慣れてきて。ソースコードを読むようになって「多分こうやれば大きく間違ってはいないはず」という、そんな指針を持てるようになりました。 Contextを要求されたら何を渡すか。重要なのは考え方、つきあい方だと思います。これが今回の記事の本題です。 私はまずライフサイクルを考えるより前に、Contextを要求するメソッドのソースコードを確認しに行きます。そいつがContextへの参照を保持するのか、それともContextを使ってなんかするだけなのか。それを確認するのです。 Contextへの参照を保持するなら、Activity Contextを渡していいのか、ライフサイクルを考えなければなりません。ライフサイクルを考えるというよりは、Activityとともに役目を終えるのか、そうでないのかで判断していますが、正直このあたりは曖昧です。 該当のメソッドが単にStringリソースを読みだすのに使っているとかだったら、別にActivity Contextを使っても問題ないですよね。そもそもActivityがリークするのは、Activityへの参照を持ち、渡した先のオブジェクトがActivityより長生きする場合だからです。 Contextへの参照を持たないのであれば、別にどっちを使おうが問題ないので、好きな方使えばいいじゃんって感じですが、Activityから呼び出すのであれば、わざわざApplication Context渡すのも大げさなので、Activity Contextでいいかと思います。 Androidと付き合っていくうちに、なんとくこんな感じに行き着きました。それでもメモリリークが怖いなら、Contextに何を使えばいいか迷うよりも、それでメモリリークするのかを確認する方に力を注いだほうが良いと思います。 でも、独学でやってるとこれで本当に問題ないのか確証が持てないので、いつもどこかで不安です。誰かに聞く機会もなくてつらい。 見えないメモリリークの影 そもそもContextについて意識し始めるキッカケは、私の場合はActivityのメモリリークです。 このメモリリークも私にとってはContext以上によく分からない存在でした。最初のうちはメモリリークしているかどうかをどうやって確認すればいいのかがわからなかったからです。確認方法が分からないから、メモリリークしないコードを書かなきゃという気持ちだけが肥大化していました。 そんな中で「とりあえずApplication Context渡しておけばライフサイクルの関係でActivityがリークすることはない」という1つの指針は、私にとっては心強かったです。 実際にはApplication Contextを渡すからメモリリークしなくなるわけではないというのは、今であれば分かります。しかしはじめの頃はそんな違いも分からなくて、そんなことよりContextとして何を渡せばいいのかという指針があることがありがたかったのです。 これに関しては、メモリリークしているかどうかを確認する方法を学ぶ方が大切だと、今であれば思いますけどね。当初は確認方法がわからないけど、メモリリークしたら困るからApplication Context渡しとけっていう感じでコード書いてました。 初学者に向けてステップアップのために 初学者がもっとも優先すべきはとりあえず先に進むことだと思います。動くアプリを作ることです。そしてAndroidに慣れることです。 Contextを要求するメソッドに対して、何らかのContextを渡す。Activity Context渡すのかApplication Context渡すのか迷うと思います。最初のうちはとりあえずどっちか渡して動いてればいいと思います。動けば正義です。迷って足を止めるより、いっぱい作ってAndroidに慣れる方が大事だと思います。 慣れてきたらContextを渡すときに「こいつはActivityより長生きする奴なのかな」と考えましょう。そんなときはソースコードを読むことが助けになると思います。 Contextを要求するメソッドは、渡されたContextをどのように使っているのか。そいつもContextが必要なメソッドを呼び出すために必要としているのか。それともContextへの参照を保持するのか。 Contextに何を使うべきなのかはケースバイケースで一概には言えません。Activity Contextじゃないとダメな場合もあれば、Application Contextの方が適切な場合もあり、はたまたどっち渡しても問題ない場合だってあります。・・・なんでこんなややこしいことになってるんでしょうね? とりあえず、動けば正義でトライアンドエラーを繰り返してAndroidに慣れる。慣れてきたらソースコードを読んでみて、Contextがどう使われているかを気にしてみる。そうやってステップアップしていくしかありません。 私のContextとの現在のつきあい方 長くなったので最後にまとめ。 私はActivity Contextを基本的に使うようにしていて、利用先でContextへの参照を持つ場合にはApplication Contextの利用を考える、というような感じでやってます。 Activity Context使っているのはThemeのためとかじゃなくて、単にgetApplicationContext()を書くと長くなるからとかそんな理由です。明らかにActivityのライフサイクルより長生きするオブジェクトに対しては、Application Context渡していますけれども。 正直な所、メモリリークをおそれてContextにどれを使うか悩むより、メモリリークの確認の仕方を調べて、リークしていないかを確認することに力入れたほうが建設的なんじゃないかなと思います。 何を使うのが適切か迷ってまごまごする前に、どう使われているのかをまず確認する。Contextの使い分けに関してはこれが私の指針なんですが、そんなに大きく間違ってはないですよね?