ブライテクノ(株)から発信する技術情報ブログです。コンテンツへスキップブライテクノBlogブライテクノ(株)から発信する技術情報ブログです。登録番号は004004となります。セキュリティ業界やスマートフォンアプリの開発の経験などをもとに、情報セキュリティ向上の業務はこれまでと同様に行ってまいります。お困りのことがございましたらご相談ください。サーバサイドからアプリ、組み込みまで広範にサポートいたします。Previewが公開されました。2へのアップデートも公開されました。6.0系よりもさらにDozeが強化されています。Googleが公開しているドキュメントによると、Dozeに段階が設けられました。6.0で導入されたDoze(深いDoze)とは別に、端末が静止1していなくてもバッテリ駆動かつスクリーンオフの状態が一定時間続くと、制限の緩いDoze(浅いDoze)に入ります。2「浅いDoze」では、アプリのネットワーク通信不可となり、ジョブ(詳しくはJobSchedulerを参照)と同期がメンテナンスウィンドウもしくはDozeの解除まで遅延されます。実際にどのくらいの時間経つと「浅いDoze」に入るのでしょうか。Preview時点ではソースコードがまだ開示されていませんので、実際の挙動から調査をしました。2を入れた状態では、以下のような挙動を確認しています。Sensorを使用しているようです。このセンサでは同じ場所で端末を振り回しても静止したままとみなされ、歩行や車などで移動することで動いたとみなされます。「深いDoze」条件が満たされた時点で「浅いDoze」の挙動から「深いDoze」の挙動に切り替わります。Erasure(型消し)」についての理解を深めるため、内容を順を追って記述していきます。Javaで書けること以下のようなコードをJavaでは書くことが可能です。Bar();fuga(foo);fuga(bar);Swiftに移植してみよう(失敗例)では、同様のコードをSwiftでも書いてみましょう。上記のコードは、コメントに示したところでコンパイルエラーとなります。これはSwiftの言語仕様の問題です。SwiftのprotocolはJavaのinterfaceと違い、クラス実装時の制約であり型ではないためです。その制約を一部解消する方法を紹介したセッションが「平常心で型を消し去る」でした。前述のJavaのようなことは(少なくとも現時点のSwiftでは)できないことも説明されていました。Erasureラッパークラスを作成することで「型を消す=(型制約の有用性を維持しつつ、同じprotocolで別の型のオブジェクトを仲間として取り扱う)」というアプローチが説明された。それが以下のようなものである。Erasure”のテクニックを用いても、Javaでできた以下のようなことはできません。something}fuga()の呼び出しに渡せる引数は、AnyBaz<X>のインスタンスでなければならず、AnyBaz<Y>やAnyBaz<Z>のインスタンスは渡せません。このこと自体はJavaも同様で、以下の場合list2はコンパイルエラーを起こします。ジェネリクスの制限としては妥当だと考えられます。Erasure”では解決できないことがあるという事実は変わらないままです。Erasureによって問題を解決できるシーンは当然あると思います。他の言語からの移植時などに、その言語でのやり方すべてをそのまま持ってこようとするのは良いアプローチではなく、そのための方法として利用するものではないとの理解をしました。簡単に持ってこられるものは持ってくるが、そうじゃないところはアプローチを変えるべきでしょう。is-a関係(継承など)ではなくhas-a関係(移譲)を用いて検討し直した方がよい場合が多いのではないかと。Playで更新されるようになりました。これにより「AndroidシステムのWebView」というアプリを更新することで、Chrome(Chromium)をベースとした、バグが修正されたWebViewを利用することができます。バグが修正されるということは、更新しておくとセキュリティ面でも安心です。WebViewを利用しているアプリは多いので、セキュリティ問題が含まれたままの古いWebViewを利用していると、なんらかの攻撃を受けるリスクはかなり高くなります。そのようなマイナスを減らすというだけではなく、更新することで新しいWeb技術を利用できるというプラスもあります。5.0以上の端末において「AndroidシステムのWebView」は是非とも更新すべきアプリの一つです。2016年2月9日版までのWebViewのクラッシュ問題(いつからかまでは特定できていませんが)2016年2月9日のバージョン48.0.2564.106までの「AndroidシステムのWebView」にはかなり重大なバグが潜んでいました。このリンク先のissueがそれを示したものなのですが、簡単にまとめると「WebViewを利用したアプリがランダムに落ちる」というものです。OpenGL関連のネイティブライブラリ内でクラッシュするようで、アプリ側で例外をキャッチして回復処理を行うということもできません。ランダムというのもくせものでした。6.0および6.0.1上でのみ発生しているようでした。一応アプリ開発する上での回避方法はありまして、以下のようにすることで回避できていました。null)これがどういうことをやっているかというと、「指定したWebViewの描画にハードウェア支援(GPUによる描画支援)を使用しない」という設定です。回避のためにこの設定を行うと、WebViewの表示が遅くなりメモリ使用量も増えるというデメリットがあります。6.0以降が搭載された端末は非常に限られていたことや、パフォーマンス問題を引き起こすことを嫌うことなどから、回避策を入れていないアプリも多いと考えられます。Mineer氏によると、49.0.2623.63がベータ版としてリリースされ、問題なければ正式にリリースされるとのことです。issueのコメントによると、49.0.2623.55には問題のworkaround(回避策)が入っていますので、正式にリリース予定のバージョンでは問題は改善している見込みです。弊社でWebViewのテスター登録を行ってベータ版をインストールしてみたところ、以前は落ちることがあったものが安定することを確認しました。6.0へのアップデートが始まります。6.0へのアップデートのお知らせが出ています。6.0が搭載されてくるでしょう。6.0になるものについては、古いWebViewが搭載されたままとなっている可能性が高いでしょう。試験にかかる時間などを考えると、2月下旬に公開されたものを組み込んだ状態でアップデートがリリースされるとは考えにくいためです。アプリ開発者はどうするべきか?6.0以降の端末である端末内の「AndroidシステムのWebView」のバージョンが古いアプリ内でWebViewを利用している上記の3つがAND条件で成立する場合、ユーザを「AndroidシステムのWebView」の更新に誘導してもよいかもしれません。ユーザはどうするべきか?「AndroidシステムのWebView」を更新しましょう。アプリがクラッシュするのを少しでも減らせるのはよいことです。2016にて「Androidの省電力について考える」というタイトルでセッションを担当いたしました。以下にその際に用いた資料を示します。上記の資料では説明しきれなかったDozeの細かい話について少しだけ補足をします。Dozeの状態遷移Dozeに入るまでの状態の変化については、同イベントでのSmartium株式会社の江川さんによるセッション資料の以下のページが参考になります。簡略的な図であり、正確な状態遷移について知りたい方はコードを追いかけてみてください。資料には状態を遷移する時間が記されていますが、その情報はDeviceIdleControllerクラスのupdateConstants()メソッドの定義を見るとよいでしょう。状態遷移についてはstepIdleStateLocked()を確認するとわかります。LOCATINGというように段階を追って遷移していくことが示されています。LOCATING後すぐにIDLE_MAINTENANCEに遷移し、一定時間後にIDLEへと遷移し、IDLEからもまた時間が経つとIDLE_MAINTENANCEへと遷移するというようなコードとなっています。Doze突入の判定と継続の条件DozeServiceクラスを読むことで、どういう条件でDozeに入るのか、またDozeが継続されるのかがわかります。17で導入されたDaydreamという機能をベースに実現されています。言いかえると「DozeServiceはDreamServceを継承したサービス」です。Daydreamはスクリーンセーバーを実現する機能であり、画面がOFFになるタイミングで働き始めます。そのタイミングから各種の条件が成立するかの監視を開始し、成立すると先に挙げた状態遷移が行われるというわけです。sensor)で端末が何かの物体と近接している場合には抜け出すトリガは捨てるという処理があります。コードを細かく見ていきコメントなども確認するとわかるのですが、これは端末がポケットやかばんに入っている場合にはDozeで省電力モードのままとするための処理です。Dozeはディープスリープか?ディープスリープは端末として最低限の電力消費まで機能を落としている状態であるとするなら、弊社で調べた限りではDoze自体がディープスリープとは言えないのではないかと考えております。いわゆるACPU(アプリが動作するプロセッサ)は動作しシステムとしてはネットワーク通信もしている状態です。除外設定されたアプリは普通に動いています。なければ高優先度のGCMを受け取って即時に対象のアプリに渡すということもできません。Dozeによる省電力に対して非協力的なアプリが多いと、省電力効果は限定的になるだろうと考えられます。そのため、Androidの将来バージョンにおいて更なる強制的な制限が行われることを避けるためにも、アプリ開発者ができるだけ省電力に対して協力的になることは非常に大事なことだと考えております。(6.0)でのActivity#shouldShowRequestPermissionRationaleの使いどころを探る注意:本記事については、弊社でもどうするのがベストプラクティスなのか掴みかねております。その点を留意してお読みください。2から、ActivityクラスにshouldShowRequestPermissionRationaleというメソッドが追加されています。rationaleとは「理論的根拠」とかそんな感じの意味があるので、このメソッドは「パーミッション要求の根拠を表示すべきかどうか」を判定するためのものであることが名前からわかります。実際、Previewのドキュメントでもそういう風に使うように記載されています。このメソッドの挙動が少し不思議です。一度も要求していないパーミッションを渡した場合、falseが返る要求したパーミッションが拒絶されたことがあり、かつ今後表示しないチェックがつけられていない場合、trueが返る要求したパーミッションが、今後表示しないというチェックを入れて拒絶された場合、falseが返る上記のような挙動になります。ここで不思議なのは1番目です。初回のパーミッション要求の前にも、そのパーミッションをどういう根拠で求めるのかはユーザに提示した方が良いのではないかと思われますが、このAPIに従った場合、表示しないというパスに流れます。Overviewに示されたコードも不思議です。return;}このコードを参考にして実装すると、shouldShowRequestPermissionRationale()の結果がtrueであったときに説明を表示します。ダイアログで表示するなどが考えられますが、その場合はダイアログ表示している間にrequestPermissions()がすでに呼び出され、外部アプリ(PackageInstallerアプリ)による権限確認ダイアログの表示に遷移してしまうことでしょう。以上から、このサンプルコードをベースに書くのはベストプラクティスでは無いだろうと考えています。いうことで、現時点ではどうするのが良いのかについてはまだ模索中です。二つの問題点とうまく折り合いをつけたベストプラクティスがGoogleから提示されることを期待しています。Mの新しいセキュリティモデル(パーミッションモデル)の記事を寄稿しました。2015年8月25日現在、紙の書籍は完売しておりますが電子書籍版はまだ頒布されています。Libraryバージョン23についても反映した内容に更新されていますが、その中では触れていない気をつけないといけない項目について、ここに記載します。Studioでデバッグ実行で試すとわかるのですが、targetSdkVersionを23にしたアプリをインストールし、それを22以下に変更して再度インストールしようとすると、以下の様な警告が表示されます。[INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE]書いてあるとおり、パーミッションモデルのダウングレードを求めるようなアプリのインストールが許可されていません。Studioは以下のようなダイアログも表示します。ここに書いてあるのは、今インストールされているアプリをアンインストールして、それからインストールするかと聞いてきています。インストール済みのアプリの保存しているデータや設定などを維持して、targetSdkVersionを22以下に落としたアプリのインストール(アップデート)を行うことはできません。Storeでも対策がなされるのではないでしょうか。一度targetSdkVersionを23以上に上げて新しいセキュリティモデルの対象となったアプリは、targetSdkVersionを上げたことによって発生したバグがあっても、22以下に戻したアプリをアップロードすることはできなくするのではないかと。既存アプリを運用されている場合、targetSdkVersionを23に変更するのは慎重に行うようにしましょう。M端末にtargetSdkVersionが22以下のアプリをインストールし、それがバージョンアップでtargetSdkVersionが23になったとしても、パーミッションが許可状態になります(Context#checkSelfPermissionがtrueを返します)。新規にtargetSdkVersionが23のアプリをインストールした場合、最初はContext#checkSelfPermissionはfalseとなりますので、そこからActivity#requestPermissionsによって権限を取得していくという流れになります。前述の場合は、targetSdkVersionが22のアプリをインストールした時点で、権限利用を許可したという状態が端末に記録され、それはtargetSdkVersionを23以上に上げた場合にも維持されます。この挙動は、iOSなどで新しいOSバージョンで権限チェックが強化された場合の挙動とは異なります。iOSでは、たとえばマイク利用にユーザによる権限確認が必要となった場合、アプリの新規インストールとアップデートのいずれであってもダイアログで確認するという挙動になります。この挙動のまま正式版となるかはわかりませんが、ユーザは気をつけておくとよいでしょう。Boosterの日高さんと一緒に書いた上記の本が5/27に発売されます。早ければ今週末くらいには書店やアマゾンから入手可能かもしれません。1なぜこんな(タイトルの)本を書いたのか?ネイティブでのAndroidアプリ開発とiOSアプリ開発の両方やっていると、それぞれのプラットフォームに違いはあっても、似ている部分も多々あることがわかります。一方の経験がもう一方の開発に生きることもよくあります。どちらのプラットフォームでも、「メインスレッド(UIスレッド)では重い処理を行ってはいけない」という原則があります。ネイティブのiOSアプリ開発ではこれまで、Objective-Cという開発言語を使用することが必須でした。前書きにも記載したのですが、個人的にはObjective-Cは非常に好きな言語の一つです。以下のような特徴があってハードルは高めだということも理解しています。C言語をベースとしているオブジェクト指向の記述方法として、C言語とは大きく異るSmalltalkライクな記法が追加されているそのようなこともあって、Androidアプリ開発の経験があってiOSアプリ開発に興味もあるけれども手を出しかねているという話もよく聞きました。マニア的にいろいろなプログラミング言語を学習してきた経験からも、ある言語での経験は新しい言語の習得に役立つことを知っています。Haskellなどのような関数型言語のようにパラダイムが大きく違う場合は、その理解に時間がかかったりもしますが、そういう場合でなければ、プログラミング言語は結構類似しているので、一つ知っていると他の言語の学習はしやすいものです。いう背景があって、本書の企画が生まれました。共通開発ではなく、それぞれを学習するのか?筆者たちが、ゲーム開発などの特定の領域を除いて、共通開発環境で複数のプラットフォーム向けに一つのアプリを開発するということのメリットがほとんどないと考えているためです。バグ改修や将来的なメンテ、機能追加などを考えると、ネイティブ開発をすることが最終的には手間がかからないと考えているためです。OSが提供する最新の面白い機能を利用しようとするなら、ネイティブ開発は必須です。iOSについて完全に一対一で対応するものがあるわけではないのですが、できるだけAndroid経験者がどういうものか理解しやすくなるように、「Androidの○○のようなもの」という説明をするようにしています。Android経験者がiOSアプリ開発を行う際の壁の一つであるUIレイアウト作成については、ページ数を割いて解説をしております。Classesについても実際にハンズオン形式で確認いただくようになっています。SwiftについてSwift言語を駆使すると非常にマニアックなことも出来るのですが、実際の現場ではそこまでマニアックな記述方法が必要になることはほとんどありません。それを踏まえて、以下の様な方針で言語仕様を解説しています。Optional型)などはしっかりと説明する言語仕様の詳細については、本書以外に、他の書籍やウェブサイトなどを参照してより深められることが望ましいと考えております。本書では何について書いていないかたくさんのことが書かれていません。Counting)で生存管理されていることについてはあまり説明していません。Counting)によってほぼ意識しないで記述できるためです。Androidアプリ開発者がiOSアプリを最初に学習する時点でそこまで説明するのは不要だろうと判断をしています。ARC以降のiOSアプリ開発では、インスタンスオブジェクトの破棄(release)を意識しないといけない場面が少ないためです。利用したUI部品のAPIを網羅的に説明するなどはしていません。API)について説明しています。標準の地図やGoogleさんのSDKやAPIを利用せず、上記を利用したのは以下の理由によります。Japanさんの地図サービスが、スマートフォン最適化され、さらに機能が充実している地図SDKで提供している機能が豊富なので、本書での学習後に独自の拡張に取り組んでいきやすい検索APIが提供する情報が豊富である追伸デザイナーさん向けに、AndroidとiOSを両方理解して、ちゃんとそれぞれに適したデザインを作る本とかどなたか出して欲しいですね。ベストセラーになってほしいです。2015年5月21日現在、東京都内のいくつかの書店(書泉ブックタワー、ジュンク堂池袋本店など)に並び始めたようです。Studioは、利用するJDKを環境変数STUDIO_JDKに設定することで切り替えることができます。Selectionで説明されています。Studioをいちいちコマンドラインから立ち上げないといけないため面倒です。そのため、ランチャー向けにSTUDIO_JDKの環境変数を設定しておく方が便利です。環境変数を記述しておくと、ランチャー向けにその環境変数が設定されました。Yosemiteからは/etc/launchd.confの設定は無視されます。Yosemite以降では、/Library/LaunchAgents以下にplistファイルを作成し、その中で環境変数を設定する必要があります。com.example.android.studio.plist)。Studioなどが公式に作成するファイルと重ならないようにつけているだけで、ご自身の好みで名前は適当に変えてください(たとえば自分の持っているドメイン名をリバースドメインで使用するなど)。使用するJDKのバージョンなどについても、ご自身が使用したいものを指定してください。インストールされているJDKを指定してください。ここでは、執筆時点でのJava8最新のJDKを指定しています。ファイルを作成したらOSを再起動すれば設定が反映されます。Studio起動時に、STUDIO_JDKに設定したJDKが使用されるようになります。OS再起動したくない場合、以下のようにすると追加したファイルの設定が追加反映されます。4.3からの隠し機能AppOpsでユーザによるパーミッション制御ができるようになっていたということを書いておりました。5.0でもAppOpsの仕組みは一部で生き残っていますが、あまり拡張されませんでした。いうものが追加されているようです。Referenceから引用します。administrator.もしかしてpermission機構とは別の仕組みで権限管理が!と期待しましたが、直交する概念だったようです。5.0から導入される仕組みとどう関係するかは要確認です。サンプルアプリがgithub上で公開されていますが、アプリごとに定義したrestrictionを管理する仕組みでしょうか。具体的な使用方法がまだイメージ出来ていません。正確な情報は調査の上で追加していく予定ですが、まずは一報だけ。