[go: nahoru, domu]

この記事は Christophe Combette, Group Product Manager, Google Ads による Ads & Commerce Blog の記事 "Preparing our partners for Apple's iOS 14 policy updates" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。

Apple がまもなく導入する App Tracking Transparency(ATT)ポリシーでは、他の企業のアプリやウェブサイトの一部の情報を広告目的で使う場合、その許可を得ることが必須となります。これには、すでにユーザーの同意を得ている場合も含まれます。iOS エコシステムのデベロッパーや広告主はまだ適応する方法を模索している状況なので、今日は Google がどのようにコミュニティの準備をサポートしているかについてお知らせします。


アプリを iOS 14 に対応させる

Apple が ATT を変更することにより、広告がどの程度コンバージョン(アプリのインストールや販売)を促進しているかを示す重要な指標の一部が見えなくなります。これは、広告主による広告インプレッションの価値評価や入札に影響します。そのため、Apple の ATT ポリシーが適用されると、アプリの発行元は、iOS での Google 広告の収益に重大な影響が発生する可能性があります。iOS の収益化率を向上するには、Google Mobile Ads SDK のバージョン 7.64 にアップグレードし、SKAdNetwork サポートなどの新機能を利用することをお勧めします。アプリの発行元が準備できることの詳細は、こちらをご覧ください


iOS 14 での広告パフォーマンスの測定

Google は、iOS 14 で広告主がキャンペーンの結果を正確に測定できるように、業界と連携して、SKAdNetwork の改善に関するフィードバックを Apple に提供しています。改善が行われるまでの間は、最新バージョンの Google Analytics for Firebase にアップグレードし、SKAdNetwork サポートなどの新機能を利用することをお勧めします。また、すべての iOS のアプリ キャンペーンのパフォーマンスや成果を細かく監視し、必要に応じて目標を達成できるように予算や入札を調整することをお勧めします。アプリの広告主が準備できることの詳細は、こちらをご覧ください。また、一連のガイドは Learn with Google 教育シリーズに掲載されています。

広告主がウェブベースのコンバージョン目標に向けてディスプレイ、動画などのキャンペーンをしている場合、Apple の ATT ポリシーが適用される際に実績が変動する可能性があります。この期間には、推定コンバージョンを拡張してより多くの iOS 14 トラフィックに対応できるようにする予定です。


ATT への準拠の仕組み

Apple のポリシーが適用されると、現在広告目的で ATT に該当する(IDFA などの)情報を利用しているいくつかの Google 製 iOS アプリで、その情報を利用できなくなります。そのため、Apple のガイドに従い、これらのアプリには ATT プロンプトは表示しません。私たちは、App Store のすべての Google 製アプリについて、Apple のガイドを理解してそれに準拠する作業を懸命に進めています。新機能やバグの修正などで Google 製 iOS アプリがアップデートされると、アプリの掲載情報ページで App のプライバシーに関する詳細情報が新しくなるのを確認できます。

Google は、常にユーザーとプライバシーを最優先しています。透明性、選択肢、制御は、ユーザーに対する私たちの献身の根底であり、それは広告でも同様です。Google は、プライバシーと選択肢が確かに尊重され、広告によってサポートされる幅広いコンテンツにアクセスでき、活発でオープンなアプリのエコシステムをこれからも守り続けます。集計ソリューションやオンデバイス ソリューションなどのプライバシー保護技術に注力し続けているのはそのためです。現在、エコシステム パートナーとともにウェブで開発しているプライバシー サンドボックスもその 1 つです。


Reviewed by Eiji Kitamura - Developer Relations Team

この記事は Google Cloud プロダクト マネージャー、Christiaan Brand による Google Online Security Blog の記事 "Making the Advanced Protection Program and Titan Security Keys easier to use on Apple iOS devices" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。

本日(元記事公開当時)より、iOS 13.3 以降を実行している Apple 端末で Google アカウントの W3C WebAuthn 実装をネイティブ サポートするための変更をロールアウトします。この機能は、個人用と仕事用の両方の Google アカウントで利用でき、対応している iOS 端末でセキュリティ キーを簡単に利用できるようにします。また、Google アカウントや高度な保護プログラムで利用できるセキュリティ キーの種類も増えます。


iPhone で NFC セキュリティ キーを利用

ユーザーのセキュリティ キーの選択肢が増加
  • USB-A と Bluetooth の Titan Security Key には、どちらも NFC 機能が組み込まれています。そのため、ログインを求められたら、キーで iPhone の後部をタップすることができます。
  • YubiKey 5Ci などの Lightning セキュリティ キーや、Apple Lightning - USB カメラアダプタをお持ちであれば任意の USB セキュリティ キーを使うことができます。
  • USB-C ポートが搭載されている iOS 端末(iPad Pro など)には、直接 USB-C セキュリティ キーを差し込むことができます。
  • Bluetooth セキュリティ キーやスマートフォンのビルトイン セキュリティ キーを使う場合は、Smart Lock アプリをインストールすることをおすすめします。これにより、iPhone を Google アカウントの追加セキュリティ キーとして使うことができます。
iOS 端末に Google アカウントを追加するには、iOS 端末で [設定] > [パスワードとアカウント] を開くか、Google アプリをインストールしてログインします。


アカウント セキュリティのベスト プラクティス


標的型攻撃に狙われる可能性が高いユーザーには、セキュリティ キー(Titan Security Key または Android や iOS スマートフォンなど)を入手して高度な保護プログラムに登録することを強くおすすめします。アメリカの政治団体で働いている方は、Defending Digital Campaigns を通して無料で Titan Security Key をリクエストし、高度な保護に登録するサポートを受けることができる可能性があります。

セキュリティ キーは、個人用や仕事用の Google アカウント1PasswordBitbucketBitfinexCoinbaseDropboxFacebookGitHubSalesforceStripeTwitter など、FIDO セキュリティ キーによる 2FA をサポートしているすべてのサイトで使うことができます。

Reviewed by Eiji Kitamura - Developer Relations Team

この記事は Firebase ソフトウェア エンジニア、Michael Hermanto による Google Developers Blog の記事 "Transitioning Google URL Shortener to Firebase Dynamic Links" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。

Google URL Shortener は、簡単にリンクを共有したり、オンライン トラフィックを測定したりする便利な方法として、2009 年にリリースされました。それ以来、たくさんの有名な URL 短縮サービスが登場しています。また、インターネット上でコンテンツを見つける方法も、主に PC のウェブページだったものが、アプリ、モバイル端末、ホーム アシスタントなどへと大幅に変化しています。

そこで、リソースの選択と集中を行うため、今後数週間で goo.gl のサポートを終了し、Firebase Dynamic Links(FDL)に置き換えます。FDL は、既存のユーザーや潜在的なユーザーに iOS、Android、ウェブアプリの任意のロケーションを送ることができるスマート URL です。今後、goo.gl のほとんどの機能は終了しますが、既存のリンクはこれからもすべて意図した宛先にリダイレクトされます

ユーザーの皆さんへ


2018 年 4 月 13 日より、匿名ユーザーと今まで短縮リンクを作ったことがないユーザーは、goo.gl コンソールから新しい短縮リンクを作れなくなりました。新しく短縮リンクを作りたい方には、Firebase Dynamic Links を使うか、代替手段として BitlyOw.ly などの有名サービスを確認することを推奨します。

既存の goo.gl 短縮リンクをお持ちの方は、2019 年 3 月 30 日までの 1 年間、goo.gl コンソールのすべての機能を利用できますが、1 年後にはコンソールの提供が終了します。それまでの間は、goo.gl コンソールからすべての短縮リンクの管理やアナリティクスを行うことができます。

すべてのリンクは、2019 年 3 月 30 日以降も意図した宛先にリダイレクトされます。既存の短縮リンクは Firebase コンソールには移行されませんが、goo.gl コンソールからリンク情報をエクスポートすることは可能です。

デベロッパーの皆さんへ


2018 年 5 月 30 日以降は、本日(*原文公開当時)までに URL Shortener API にアクセスしたことがあるプロジェクトでのみしか短縮リンクを作成できません。新しく短縮リンクを作成する場合は、FDL API を使うことを推奨します。FDL 短縮リンクは、自動的にユーザーのプラットフォームを検知し、ユーザーを適切なウェブまたはアプリに転送します。

すでに URL Shortener API を呼び出して goo.gl 短縮リンクを管理している方は、API の提供が終了する 2019 年 3 月 30 日までの 1 年間、利用を続けることができます。

ユーザーについては、すべてのリンクは 2019 年 3 月 30 日以降も意図した宛先にリダイレクトされます。ただし、既存の短縮リンクは Firebase コンソール / API には移行されません。

URL Shortener はすばらしいツールで、これを構築できたことは私たちの誇りです。しかし、未来に視野を向ければ、Firebase Dynamic Links が持つ可能性への期待は高まるばかりです。特に、動的なプラットフォーム検知や、アプリのインストール プロセスをはさんでも動作するリンクはすばらしいものです。皆さんにもそう思っていただけたらと思います。

 

Reviewed by Takuo Suzuki - Developer Relations Team

この記事は Seth Ladd、Product Manager for Flutter による Google Developers Blog の記事 "Announcing Flutter beta 1: Build beautiful native apps" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。

元の記事は、Seth Ladd が Flutter の Medium に投稿したものです

本日(*原文公開当時)はうれしいことに、Mobile World Congress 2018 で、Flutter の最初のベータ版リリースについてお知らせしました。Flutter は、Google の新しいモバイル UI フレームワークです。これを使うと、開発者は iOS と Android の両方で高品質なネイティブ インターフェースを作り上げることができます。早速、flutter.io から美しいネイティブ アプリを作ってみましょう



Flutter は、モバイル開発を最も効率よく行えるように、高いパフォーマンスとプラットフォームとの統一感、そしてポータブル UI ツールキットによる高速開発とマルチプラットフォームへの対応といった特徴を持っています。



Flutter は、これからモバイルアプリの開発を行う開発者と、既にモバイルアプリ開発の経験がある開発者の両方を対象に設計されました。次のようなメリットを備えているので、高速に美しく質の高いアプリを構築できます。
  • ステートフル ホット リロード、新しいリアクティブ フレームワーク、高機能なウィジェット セット、統合ツールなどの機能を活用した高速開発
  • 組み合わせ可能なウィジェット セット、高機能アニメーション ライブラリ、レイヤー対応の拡張可能アーキテクチャによる表現力の高い柔軟なデザイン
  • GPU アクセラレーションに対応したポータブル レンダラーと高パフォーマンスなネイティブ ARM コード ランタイム、そしてプラットフォームの相互運用性による端末やプラットフォームを問わない高品質エクスペリエンス

昨年のアルファ リリース以降、コミュニティの力も借りて、スクリーン リーダーやその他のユーザー補助機能のサポート、右から左へのテキスト、ローカライズと国際化、iPhone X と iOS 11 のサポート、インライン動画、サポート対象となる画像形式の追加、バックグラウンドでの Flutter コードの実行など、多くの機能を提供してきました。

また、Android Studio Visual Studio Code のサポート、新たなリファクタリングによるウィジェットのコード管理、モバイル プラットフォームの力を Flutter コードから利用できるようにするためのプラットフォームの相互運用性、ステートフル ホット リロードの改善、ウィジェット ツリーを表示する際に便利な新しいウィジェット インスペクターなど、ツールも大幅に改善されています。



さまざまなフレームワークやツールの新機能のおかげで、Google(AdWords など)や世界中のチームが Flutter で成功を収めています。Flutter はすでに本番環境のアプリで使われており、数百万単位でインストールされています。Flutter で構築したアプリは App Store や Play Store(Hamilton: The Musical など)でも取り上げられ、スタートアップや開発会社も Flutter で成功を収めています。

たとえば、フィンランドの開発会社 Codemate は、Flutter の高速な開発サイクルとカスタマイズ可能な UI ツールキットを活用し、Hookle の美しいアプリを短時間で開発しました。Codemate の CEO、Toni Piirainen 氏は、「お客様の業績に貢献し、モバイル ユーザーに高い価値を提供できるように、自信をもって Flutter をおすすめしています」と話しています。



Flutter で開発したアプリは、さまざまなプラットフォームで品質、パフォーマンス、そしてカスタマイズできるデザインを実現します。

Flutter のベータ版では、Dart 2プレリリース版も動作します。コードからの UI の宣言が最低限の記述量で行えるよう改善されています。たとえば、Dart 2 は newconst を推論できるので、UI 構築時のボイラープレートを削減できます。次に例を示します。

// Before Dart 2
Widget build(BuildContext context) {
  return new Container(
    height: 56.0,
    padding: const EdgeInsets.symmetric(horizontal: 8.0),
    decoration: new BoxDecoration(color: Colors.blue[500]),
    child: new Row(
      ...
    ),
  );
}

// After Dart 2
Widget build(BuildContext context) =>
  Container(
    height: 56.0,
    padding: EdgeInsets.symmetric(horizontal: 8.0),
    decoration: BoxDecoration(color: Colors.blue[500]),
    child: Row(
      ...
    ),
  );


Flutter のエコシステムの繁栄を目の当たりにして、私たちも興奮しています。Flutter で動作するパッケージは 1000 以上SQLiteFirebaseFacebook Connect共有プリファレンスGraphQL 他多数)にのぼり、チャットには 1700 名以上が参加しています。コミュニティによって、Flutter InstituteStart FlutterFlutter Rocks などの新しいサイトが生まれていることもうれしく思います。さらに、コミュニティが編集、発行する新しい Flutter Weekly ニュースレターを購読することもできます。

現在は、1.0 リリースを見据えて、安定化とシナリオの補完に重点的に取り組んでいます。Flutter のロードマップは、コミュニティに大いに触発されています。現在は、Flutter の既存アプリへの埋め込みの簡易化、インライン WebViewルーティングおよびナビゲーション API の改善Firebase サポートの追加インライン マップコアエンジンの小型化といった機能に取り組んでいます。約 4 週間ごとに新しいベータ版をリリースする予定です。また、ぜひとも Issue Tracker で皆さんや皆さんのアプリにとって重要な問題に投票(👍)してください。

今こそ、Flutter を試してみる最善のタイミングです。スタートガイドを参照すると、まったく初めての方でも短時間で初めての Flutter アプリを実行できます。すでに Flutter をインストールしている方は、こちらの手順に従ってベータ版チャンネルに切り替えることができます。

皆さんのサポート、フィードバック、そして多くの貢献に心から感謝申し上げます。この旅を皆さんとともに続けられること、そして皆さんのアプリがリリースされることを楽しみにしています!



Reviewed by Takuo Suzuki - Developer Relations Team

この記事は Erik Pasternak とキッズ コーディング チームによる Google Developers Blog の記事 "Introducing Blockly 1.0 for Android and iOS" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。

Blockly はブロックベースのコーディング体験を提供するオープンソース ライブラリです。この 5 年間で、デベロッパーは Blockly を使って、Code.org のような教育プラットフォームから、littleBits のような電子工作キット、MIT App Inventor のような Android アプリ作成ツールまで、何百ものプロジェクトを生み出してきました。昨年には、Scratch チームと協力して Scratch Blocks を開発したこともお知らせしました。これは Blockly をソースをフォークして作られたもので、子供向けアプリのコーディングに最適化されています。

本日(*原文公開当時)は、Android と iOS で Blockly のリリース 1.0 が完成したことをお知らせします。Blockly 1.0 には、モバイルアプリでネイティブに Blockly を使うために必要な次のものがすべてがそろっています。
  • Blockly の標準 UI
  • カスタム ブロック、ツールボックス カテゴリ、レイアウト
  • 関数、変数、ミューテーター、エクステンション
  • JavaScript、Python、Dart、PHP、Lua コード生成
  • 国際化サポート(RTL 言語も含む)

本日の 1.0 へのアップデートは、ネイティブのモバイル環境を主眼に置いたものですが、ウェブ版のプロジェクトもここ半年でいくつかのアップデートが行われています。パフォーマンスとテストは大きく改善されており、構造的な API が追加され、モバイルウェブでのタッチ機能のサポートも改善されています。さらに、Internet Explorer と Edge のサポートも強化され、IE10 以上で Blockly が完全にサポートされています。

また、クロス プラットフォーム開発を容易にするために、さまざまな作業も行われています。ブロックはすべて JSON で定義できるようになったので、1 つのブロック定義をウェブ、iOS、Android で使い回すことができます。これら 3 つのプラットフォームの詳細については、ドキュメントをご覧ください。


iOS コードラボは、すぐにご利用いただけます(Android 版も近日中に提供予定)。Blockly の詳細については、上の紹介ビデオデベロッパー サイトをご覧ください。また、メーリング リストにもご参加ください。ウェブAndroidiOS のコードを直接参照することもできます。



Reviewed by Takuo Suzuki - Developer Relations Team

この記事は プロダクト マネージャー 、Jumana Al Hashal  による The Firebase Blog の記事 "Making Dynamic Links Easier" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。


Firebase Dynamic Links は便利なリンクシステムです。1 つだけのリンクで、インストール済みの iOS や Android アプリを開き、ディープリンクを使用し、ユーザーが探しているコンテンツを直接にアプリ内で表示することができます。アプリがインストールされていない場合にも、同じリンクで App Store や Google Play のアプリのページからアプリ内のコンテンツまで案内することができます。

私たちは 1 年前からこの機能を改善し、よりスムーズでよりパワフルな体験をデベロッパー、ユーザーの両方に届けられるよう努力してきました。今回、最新の機能を iOS SDK と Android SDK に届けることができたことを嬉しく思います。

Dynamic Links をダイナミックに生成する


今まで、Dynamic Links を生成するには Firebase コンソールからアクセスする必要がありました。広告、宣伝などのキャンペーンの目的では十分でしたが、デベロッパーの皆さまからは、ユーザー同士で共有できるキャンペーンなどに対応するために、アプリからリンクを作成できるようにしたいというフィードバックを多数いただいていました。

そのため、iOS と Android の Firebase SDK に、ロングとショートの Dynamic Link を生成する機能を追加しました。

iOS:

guard let deepLink = URL(string: "https://mydomain.com/page?param=value") else { return }

let components = DynamicLinkComponents(link: deepLink, domain: domain)

let iOSParams = DynamicLinkIOSParameters(bundleID: bundleID)
iOSParams.minimumAppVersion = minVersion
components.iOSParameters = iOSParams

// ダイナミック リンクを生成する
let link = components.url

// またはショート リンクを生成する
components.shorten { (shortURL, warnings, error) in
      if let error = error {
        print(error.localizedDescription)
        return
      }
      
    // TODO: shortURL を使用する
    }

Android:

String deepLink = "https://mydomain.com/page?param=value";

DynamicLink.Builder builder = FirebaseDynamicLinks.getInstance()
        .createDynamicLink()
        .setDynamicLinkDomain(domain)
        .setAndroidParameters(new DynamicLink.AndroidParameters.Builder()
                .setMinimumVersion(minVersion)
                .build())
        .setLink(deepLink);

// ダイナミック リンクを生成する
DynamicLink link = builder.buildDynamicLink();

// またはショート リンクを生成する
builder.buildShortDynamicLink()
        .addOnSuccessListener(new OnSuccessListener() {
            @Override
            public void onSuccess(ShortDynamicLink shortDynamicLink) {
                // shortDynamicLink を使用する
            }
        });

新しい Android API

アプリから Dynamic Links を実装しやすくするために Android API を考え直して、新たに FirebaseDynamicLinks というクラスを追加しました。新しいライブラリを追加するには、build.gradle に次の行を追加します。


compile "com.google.firebase:firebase-dynamic-links:11.0.0"

これによって、Dynamic Link から起動したアクティビティを開く際の処理が簡単になります。

FirebaseDynamicLinks.getInstance().getDynamicLink(getIntent())
  .addOnSuccessListener(
    new OnSuccessListener() {
      @Override
      public void onSuccess(PendingDynamicLinkData data) {
      if (data == null || data.getLink() == null) {
        // FDL は特にない。何もする必要がない
        return;
      }

      Intent launchIntent = data.getUpdateAppIntent(MainActivity.this);
      if (launchIntent != null) {
        startActivity(launchIntent); // アップグレード フローを起動する
      }

     Uri deepLink = dynamicLink.getLink();
     String myAppItemId = deepLink.getQueryParameter("myAppItemId");
     // TODO: myAppItemId のコンテンツを表示する
    }
});

新しい API に関するご質問やフィードバックがあった場合は、サポートページをご確認ください


Reviewed by Oscar Rodríguez - Developer Relations Team

この記事は マテリアル デザイン、Adrian Secord および Omer Ziv による Google Developers Blog の記事 "Build beautiful apps and websites with modular, customizable UI components " を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。  
 
マテリアル コンポーネントはオープンソースで公開されているライブラリです。マテリアルコンポーネントを使うと、Android, iOS, Web でマテリアル デザインのガイドラインに沿った、統一感のあるスタイル、ブランド、インタラクション、モーションを使ったアプリケーションを簡単に開発できます。  
 
これらのコンポーネントは、最新のマテリアル デザインのガイドラインに沿うようにエンジニアとデザイナーのチームにより定期的に更新され、多言語対応やアクセスビリティのサポートなどの基準を満たす高品質な実装を行う事ができます。  

デザインの精度
Android、iOS、ウェブのそれぞれのプラットフォームにピクセル単位で準拠したコンポーネントです。

最新
コンポーネントは常に最新の API と機能が利用できるよう、Google のエンジニアとデザイナーがアップデートを行なっています。

オープンソース
コードは GitHub 上で公開されています。これを利用してマテリアル デザインに貢献したり、必要に応じて要素を使うことも可能です。


業界標準
Google の各種サービスにも使われているこれらのコンポーネントは、多言語化やアクセスビリティなどの業界標準を満たしています。

マテリアル コンポーネントは、Google の Android、iOS、およびウェブのエンジニアおよび UX デザイナーのコアチームにより開発保守されています。以下の取り組みにより、各プラットフォームに向けた最大限のサポートに努めています。
  • 様々な Android OSバージョンのサポート
  • Swift、Objective-C、ストーリーボードなどの業界標準を使った iOS アプリの開発
  • 一般的なフレームワークやライブラリを使用したシームレスな統合

これらのコンポーネントにより、マテリアル デザインを使った優れたユーザー エクスペリエンスを持ったアプリを簡単に開発できます。今後私たちは、最新のマテリアル デザインのガイドラインに合致するコンポーネントを継続的に更新していきます。またオープンソースで公開していますので、開発者の皆さんのチームがこのプロジェクトに貢献することを期待しています。最新のニュースを受け取りたい方や、直接私たちに連絡したい方は、私たちの GitHub リポジトリをチェックするか、Twitter(@materialdesign)をフォローするか、https://material.io/components/ をご覧ください。


Posted by Takuo Suzuki - Developer Relations Team

この記事は Todd Kerpelman、デベロッパー アドボケートによる The Firebase Blog の記事 "Debugging Firebase Cloud Messaging on iOS" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。


Todd Kerpleman


Todd Kerpelman
Developer Advocate
Firebase Cloud Messaging のデバッグは、iOS での Firebase の利用に関する StackOverflow の質問の中でもっともよく目にするものの 1 つです。そのため、できるだけ StackOverflow のポイントを稼ぐために(そしてもちろんデベロッパー コミュニティの成長のために)、Firebase Cloud Messaging(FCM)が iOS 端末でうまく動作しない場合にどうすればよいか、完全なデバッグガイドをまとめておきたいと思います。まず、少しばかり時間をとって、iOS での FCM を理解するための動画(英語)を見てみることをお勧めします。FCM の内部で何が行われているかがわかりますので、この点を知っておくとデバッグに役立ちます。では、どうぞ。お待ちしています。



見終わりましたか?動画の説明から、複数のシステムが相互通信を行っていることがわかったのではないかと思います。
  1. アプリサーバー(または Firebase Notifications)が Firebase Cloud Messaging と通信
  2. 次に、Firebase Cloud Messaging が APNs と通信
  3. APNs がユーザーの対象端末と通信
  4. ユーザーの対象端末上で、iOS がアプリと通信

これら 4 つの通信パスがあるということは、うまく動作しない可能性のある箇所が 4 つあるということです。そのため、「通知は送信されたと言っているのに、端末には何も表示されない」という事態が発生する場合、解決するために詳しい調査が必要になります。ここでは、こういったエラーを調査する際にお勧めの手順を紹介しましょう。

1. すべての connectToFCM() の呼び出しを一時的に無効にしてみる

先ほどの動画では、アプリがフォアグラウンドにある場合、connectToFCM() を呼び出して明示的に Firebase Cloud Messaging に接続できることが紹介されていました。この方法を使うと、アプリは content-available フラグがないデータのみのメッセージを直接 FCM から受信できます。
この機能は状況によっては便利かもしれませんが、デバッグ中は無効にしておくことをお勧めします。これは、単に 1 つの余分な要素を排除するためです。私は何回か、「フォアグラウンドでは通知を受信できるが、バックグラウンドではできない」という問題を目にしてきました。これはおそらく、実際には APNs の設定がうまくいっておらず、FCM チャンネル経由でのみメッセージを受信しているために発生しています。
この時点でうまく動かない場合: 元々の「フォアグラウンドでは通知を受信できた」状態から「通知が一切届かなくなった」という状態になった場合、最初からアプリで APNs から通知を受信できるように正しく設定されていなかったという印です。そのため、アプリは以前よりもさらに動かなくなっているかもしれませんが、少なくとも現在は一貫して動かなくなっているはずです(よかったですね!)。APNs の実装をデバッグするには、引き続き以降をお読みください。
次のいくつかのステップでは、「Notifications、FCM、APNs、iOS、アプリ」という連鎖を逆方向にたどってゆきます。ではまず、iOS が実際にアプリと通信できているかを確認するところから始めましょう。

2. 懐かしの print() デバッグを追加してみる

Firebase Cloud Messaging は、メソッド スウィズリング(メソッドの入れ替え)という賢い方法を使って、AppDelegate で application(_:didRegisterForRemoteNotificationsWithDeviceToken:)application(_:didFailToRegisterForRemoteNotificationsWithError:) をまったく実装しなくてもよい仕組みを実現しています。
しかし、デバッグをする際には、気づくべきエラーが起こっていないかを確認するために、これらのメソッドを追加して何らかのデバッグ情報を表示したい場合があります。まずは、失敗した場合に呼ばれるメソッドにいくつかのデバッグ出力を追加してみましょう。たとえば、次のようなものです。

func application(_ application: UIApplication,
    didFailToRegisterForRemoteNotificationsWithError error: Error) {
  print("Oh no! Failed to register for remote notifications with error \(error)")
}
理論上、ここで何らかのエラー メッセージが表示された場合は、FCM クライアント ライブラリからもメッセージが出力されるはずですが、ここではあえて独自のメッセージを追加しましょう。こうすれば、Xcode の出力で特定の文字列(たとえば、先ほどの例の「Oh no!」)を検索できるためです。また、こうしておくと、その行にブレークポイントを貼れるので便利です。
さらに、didRegister... メソッドで端末トークンを人間が読める形で表示するようにしてみましょう。
func application(_ application: UIApplication,
    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
  var readableToken: String = ""
  for i in 0..<deviceToken.count {
    readableToken += String(format: "%02.2hhx", deviceToken[i] as CVarArg)
  }
  print("Received an APNs device token: \(readableToken)")
}
デバッグ メソッドを追加するために、メソッド スウィズリングを無効にしたりする必要はありません。Firebase は、独自のメソッドを呼び出した後、自動的にこれらのメソッドを呼び出してくれます。
この時点でエラー メッセージが表示された場合: エラー メッセージが表示された場合や、端末トークンが返されなかった場合は、エラー メッセージを確認すると、何がうまくいっていないかを突き止めるよい手がかりが得られます。この時点でよく起こるのは、「動かなかった理由を他の人に説明したくない」タイプの失敗です。たとえば、次のようなものです。
  • 実機でなく、iOS シミュレータでテストしていた
  • Xcode のプロジェクト設定で、プッシュ通知を有効にし忘れていた
  • アプリの起動時に application.registerForRemoteNotifications() を呼び出していなかった
お分かりだと思いますが、これらは単純なミスです。しかし、Xcode のコンソールにメッセージを表示しなければ、気づかないままになることも多いでしょう。

3. ユーザーに表示される通知を送信できることを確認する

iOS アプリで通知のアラートを表示したり通知音を鳴らしたりするには、明示的にユーザーのパーミッションを取得する必要があります。アプリでバックグラウンドの通知メッセージを受信できていないように見える場合は、単にアプリに iOS のパーミッションがないだけの可能性があります。
iOS 10 以上の場合、アプリのどこかに次のコードを追加するとこの点を確認できます。
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
  print("Alert setting is \(settings.alertSetting ==
    UNNotificationSetting.enabled ? "enabled" : "disabled")")
  print("Sound setting is \(settings.soundSetting ==
    UNNotificationSetting.enabled ? "enabled" : "disabled")")
}
この時点で「disabled」メッセージが表示された場合: アプリが通知を出すためのパーミッションを意図せずに拒否してしまったか、そもそもパーミッションを取得しようとしていなかったかのどちらかが原因です。
アプリが通知を出すためのパーミッションを尋ねてきたときに、意図せず「許可しない」ボタンをタップしてしまった場合は、[設定] を開いて自分のアプリを探し、[通知] をクリックして [通知を許可] スイッチを切り替えると、問題を修正できます。

                                   

一方で、ユーザーに表示される通知を出すためのパーミッションを要求していなかった場合は、アプリのどこかに次のようなコード(iOS 10 以上)を追加する必要があるということです。
let authOptions : UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions)
  { (granted, error) in
    if (error != nil) {
      print("I received the following error: \(error)")
    } else if (granted) {
      print ("Authorization was granted!")
    } else {
      print ("Authorization was not granted. :(")
    }
  }
この時点で何の問題もないように見える場合は、APNs 接続のデバッグに進みましょう。

4. 直接 APNs を呼び出してみる

通知の処理に FCM を使っていても、直接 APNs を使うことは可能です。これはいくつかの方法で試すことができます。その 1 つは、NWPusher のようなオープンソース ツールを使ってテスト通知を送信してみることです。しかし、個人的には、curl を呼び出して直接 APNs リクエストを送信する方がいいと思っています。
現在の APNs は HTTP/2 をサポートしているので、APNs に curl リクエストを行う方が簡単です。しかし、そのためには、curl が最新バージョンになっている必要があります。最新かどうかは、curl --version を実行すると確認できます。おそらく、次のように表示されるはずです。
curl 7.47.1 (x86_64-apple-darwin15.6.0) libcurl/7.47.1 OpenSSL/1.0.2f zlib/1.2.5 nghttp2/1.8.0
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets
APNs と通信するには、7.43 以上のバージョンの curl が必要で、Features に HTTP2 が含まれている必要があります。curl のバージョンがこの要件を満たさない場合は、アップデートする必要があります。Simone Carletti 氏によるこちらのブログ投稿には、その手順が丁寧に示されています。
次に、Apple Developer Portal からダウンロードした .p12 ファイルを .pem ファイルに変換します。これを行うには、次のコマンドを使用します。
openssl pkcs12 -in MyApp_APNS_Certificate.p12 -out myapp-push-cert.pem -nodes -clcerts
さらに、対象端末の APNs 端末トークンも必要です。先ほどの application(_:didRegisterForRemoteNotificationsWithDeviceToken:) メソッドに掲載したデバッグ テキストを追加している場合は、Xcode のコンソールから端末トークンを取得できます。これは、ab8293ad24537c838539ba23457183bfed334193518edf258385266422013ac0d のように表示されています。
これで、curl を呼び出すことができます。次の例をご覧ください。
> curl --http2 --cert ./myapp-push-cert.pem \
-H "apns-topic: com.example.yourapp.bundleID" \
-d '{"aps":{"alert":"Hello from APNs!","sound":"default"}}' \
https://api.development.push.apple.com/3/device/ab8293ad24537c838539ba23457183bfed334193518edf258385266422013ac0d
ここでは、3 つの点に注意します。
  1. --cert 引数には、先ほどの手順で作成した .pem ファイルを指定します。
  2. apns-topic には、アプリのバンドル ID を指定してください。なお、apns-topic の概念は、Firebase Cloud Messaging のトピックとはまったく異なる概念なので、ご注意ください。
  3. URL の最後には、忘れずに端末トークンを含めるようにします。上の例をコピーして貼り付けるだけでは動作しません。
うまく動作すれば、端末にプッシュ通知が表示されるはずです。その場合は、次のステップに進んでください。動作しない場合、以下の点を確認します。
  1. APNs から何らかのエラー メッセージが返されましたか?その場合は、何かがうまくいっていないという印です。よく見られるのは、次のようなメッセージです。
    1. 「Bad device token」 -- メッセージにあるとおり、端末トークンが間違っています。アプリから正しくコピーできているかどうかもう一度確認してください。
    2. 「Device token not for topic」 -- アプリのバンドル ID にトピックが正しく設定されていない可能性があります。または、正しい証明書を使っていない可能性もあります。私の経験では、間違った .pem ファイルを使ったとき、このメッセージが表示されたことがあります。
  2. アプリはバックグラウンドで動作していますか?アプリがフォアグラウンドで動作している場合、iOS は自動的に通知アラートを表示したり、通知音を鳴らしたりしません。
    1. ただし、iOS 10 では、アプリがフォアグラウンドで動作しているときも、かなり簡単にアラートを表示できるようになっています。userNotificationCenter(_:willPresent:withCompletionHandler:) の最後で completionHandler([.alert]) を呼ぶだけで、これを行うことができます。
  3. 有効な APNs リクエストを送信していますか?いくつかのリクエストは、構文的に正しくても拒否される可能性があります。この投稿の執筆時点では、content-available フラグを含まないサイレント通知の送信や、優先度 high のサイレント通知の送信などがこれにあたります。
    1. さらに、サイレント通知を受信したアプリが妥当な時間内に completionHandler を呼び出さない場合や、通知の処理に電池を使いすぎる場合、iOS によってサイレント通知が制限される場合があります。詳しくは、Apple のドキュメントをご覧ください。
  4. APNs に問題が起きていませんか?念のため、APNs と APNs Sandbox のステータスを https://developer.apple.com/system-status/ で確認してください。
うまく動作していると思われる場合は、次のステップに進みます。

5. curl で直接 FCM を呼び出してみる

APNs の呼び出しがうまく動作していることが確認できたら、次のステップでプロセスの FCM 部分が動作していることを確認します。そのために、もう一度 curl 呼び出しを行います。これを動作させるには、サーバーキーと、対象端末の FCM 端末トークンの 2 つが必要です。
サーバーキーを取得するには、Firebase コンソールのプロジェクトで Cloud Messaging の設定を開きます。175 文字の長い文字列で表示されているのがサーバーキーです。



FCM 端末トークンの取得には、少しばかり作業が必要です。アプリは、最初に APNs トークンを受信したとき、それを FCM サーバーに送信し、それと引き替えに FCM 端末トークンを受け取ります。この FCM トークンが戻されると、FCM ライブラリは「インスタンス ID トークン更新」通知を行います。 1
この通知(firInstanceIDTokenRefresh の NSNotification)を受け取ることができれば、FCM 端末トークンを確認できますが、この通知は端末トークンが変更された場合にしか発行されません。これは頻繁に起こるものではなく、デバッグビルドから本番ビルドに切り替えたときや、初めてアプリを実行したときのみ行われます。それ以外の場合、この通知は発生しません。
ただし、キャッシュされた FCM 端末トークンを取得することは可能です。InstanceID ライブラリを使うと、保存されているあらゆる端末トークンを取得できます。ここでは、最新の FCM トークンを取得してみます。次のようなコードを書いてみましょう。
  func application(_ application: UIApplication, didFinishLaunchingWithOptions
    // ...
    printFCMToken() // This will be nil the first time, but it will give you a value on most subsequent runs
    NotificationCenter.default.addObserver(self, 
      selector: #selector(tokenRefreshNotification), 
      name: NSNotification.Name.firInstanceIDTokenRefresh, 
      object: nil)
    application.registerForRemoteNotifications()
    //...
  }

  func printFCMToken() {
    if let token = FIRInstanceID.instanceID().token() {
      print("Your FCM token is \(token)")
    } else {
      print("You don't yet have an FCM token.")
    }
  }

  func tokenRefreshNotification(_ notification: NSNotification?) {
    if let updatedToken = FIRInstanceID.instanceID().token() {
      printFCMToken()
      // Do other work here like sending the FCM token to your server
    } else {
      print("We don't have an FCM token yet")
    }
  }
アプリを初めて実行すると、FCM トークンがないというメッセージが表示され、そのすぐ後に実際のトークンを含むメッセージが表示されます。2 回目以降の実行では、キャッシュされたトークンがすぐに表示されます。これは 153 文字のランダムな文字列です。サーバーキーとよく似ていますので、混同しないようにしてください。
これで必要な情報がそろったので、curl を呼び出せるようになります。次のような呼び出しを行ってみてください。
> curl --header "Content-Type: application/json" \
--header "Authorization: key=AU...the rest of your server key...s38txvmxME-W1N4" \
https://fcm.googleapis.com/fcm/send \
-d '{"notification": {"body": "Hello from curl via FCM!", "sound": "default"},
"priority": "high",
"to": "gJHcrfzW2Y:APA91...the rest of your FCM token...-JgS70Jm"}'
うまくいけば、端末に通知が表示され、FCM から「Success」というレスポンスを受け取ります。
{"multicast_id":86655058283942579,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1486683492595106961%9e7ad9838bdea651f9"}]}
成功というレスポンスがあっても、喜びすぎてはいけません。これでわかるのは、FCM がメッセージを正常に受け取ったというだけです。FCM が APNs にメッセージをうまく送信できたとは限りません。本当に必要なのは、端末上の通知です。
通知をうまく受け取れていないと思われる場合、次の点を確認します。
  • レスポンスにエラー メッセージが表示されていますか?それを無視してはいけません。こういったメッセージは、何が起きているのかを理解するための大きなヒントになります。
    • InvalidRegistration が表示された場合、FCM 端末トークン(実際は「registration token」と呼ばれています)が正しくありません。
    • 「The request's Authentification (Server-) Key contained an invalid or malformed FCM-Token」というメッセージとともに 401 エラーが返された場合、おそらくサーバーキーが正しくありません。文字列全体を Firebase コンソールから正しくコピーしていることを確認してください。
  • priorityhigh に設定していますか?Android 端末と iOS 端末では、優先度 medium と high の解釈が異なります。
  • Android では、優先度 medium は「メッセージは送るが、ユーザーの端末が Doze モードになっている場合、それを考慮する」という意味になります。これは、優先度を指定しなかった場合、FCM はデフォルトの優先度「medium」を使用するためです。
    • iOS では、優先度 medium(または 5)が意味するのは、せいぜい「そのうち通知するかもしれない。でも、このおかしな世界では、確実なことなど何も言えないよ ¯\_(ツ)_/¯」といった感じです。
    • これは、優先度を指定しなかった場合、APNs のデフォルトの優先度が 10(または「high」)になるためです。また、優先度 medium でメッセージを送るよう求められるのは、データのみの content-available メッセージを送る場合だけです。
    • ほとんどのユーザーに表示されるメッセージは、Android 端末では優先度 medium で、iOS 端末では優先度 high で送るのが理想的です。Firebase Notifications の通知パネルを使うと、とても簡単にこれを行えます。
  • FCM 構文ではなく APNs 構文を使っていませんか?FCM は、FCM の言葉を適切に APNs の言葉に変換するようになっているものの、最初から APNs 構文を送信すると、FCM はそれを正しく認識できません。そのため、FCM 向けの正しいフォーマットでメッセージを送信しているかを再度確認してください。特に、「priority」が「10」でなく「high」に設定されていることを確認します。
    • content-available メッセージを送信する場合、"content-available": ではなく、アンダースコアを使って "content_available": true を指定していることを確認します。2
    • この時点で、Firebase Notifications の通知パネルを使って通知を送信してみるとよいでしょう。Notifications 経由で呼び出すことができ、curl では呼び出せない場合、メッセージが正しくフォーマットされていない印かもしれません。
  • Firebase コンソールに APNs 証明書をアップロードしましたか?その有効期限が切れていませんか?FCM が APNs と通信するためには、証明書が必要です。
6. Firebase Notifications の画面やサーバーから呼び出してみる

ここまできた場合、基本的に FCM、APNs、iOS、アプリというパスが確立されており、うまく動作しています。そのため、この時点で Firebase Notifications 画面から送られる通知がうまく動作しないのであれば、それは驚くべきことです。その場合、status.firebase.google.com を確認し、Cloud Messaging サービス(Notifications も含まれます)に何らかの問題が発生していないかを調べてみるとよいでしょう。
サーバーのコードに問題があるなら、それはお使いのサーバーで対応する必要があります。しかし、正しい FCM 呼び出しを行うために生成する必要があるデータについて正確に理解できたと思いますので、この部分は皆さん自身で十分解決できるでしょう。少なくとも、自信があるふりはできるでしょう。ほとんどの人はそれでごまかすことができます。

お疲れ様でした。長い道のりでしたが、ステップ 2 で Xcode のプロジェクトのスイッチを切り替え忘れていた、というようなことに気づいていただけたなら幸いです。そういう方は、おそらくこのまとめの部分は読んでいないでしょう。考えてみれば、ここまで読んでいる皆さんは、おそらくまだ実装上解決されていない問題があるということでしょう。その場合は、サポート チャンネルもご覧ください。または、この時点では、基本的に私はすでにアドバイスできることはありませんので、@lmoroney に質問してください。

お読みいただき、ありがとうございました!

[1] これは APNs 通知ではなく、NSNotification です。用語がややこしいですね。
[2] 1 つの興味深いエラーを紹介しましょう。あるデベロッパーは、どういうわけか、アプリがフォアグラウンドにある場合のみ content-available メッセージを受信できると言っていました。そのデベロッパーは、(ステップ 1 のように)FCM に明示的に接続しており、メッセージに(無効な)"content-available" キーを含めて送信していました。これは有効な APNs の content-available メッセージに変換できないため、FCM は FCM 経由だけで送信されるべきデータのみのメッセージと解釈しました。そのため、アプリがフォアグラウンドにある場合だけ動作していました。


Posted by Khanh LeViet - Developer Relations Team

この記事は Hoi Lam、デベロッパー アドボケートによる Android Developers Blog の記事 "Final Android Wear 2.0 Developer Preview: iOS support. Time to upload your apps to the Play Store!" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。


Telegram Messenger のクロス プラットフォーム サポート

本日(*原文公開当時)、Android Wear 2.0 の 5 回目にして最終となるデベロッパー プレビューをリリースします。このリリースには、iOS サポートが追加されているほか、多くのバグの修正や機能拡張が含まれています。このプレビューを使ってアプリをコンパイルすると、Google Play ストアに提出する準備は完了です。ついにアプリを公開するときがやってきました。2 月上旬に予定されている Android Wear 2.0 の最終リリースが近づいてきました。デベロッパー プレビュー プログラムで継続的にフィードバックを寄せてくださった皆さんに感謝いたします。皆さんからのフィードバックは、バグを見つけたり製品について重要な意思決定を下すために役立っています。ありがとうございました!

iOS のサポート


2015 年以降、Android Wear ウォッチと iPhone のペア設定が可能になっています。そして今回より、iPhone とペア設定した時計にもアプリを配布できるようになります。これは、ウォッチアプリのマニフェストに standalone=true フラグを設定するだけで実現できます。この設定によって、ウォッチアプリに Android スマートフォン アプリが不要であることが Play ストアに認識され、iPhone とペア設定された時計の Play ストアにウォッチアプリが表示されるようになります。こちらの手順を実行するだけで、時計を iPhone とペア設定してテストできます。

プラットフォームで電池の節約とネットワークの帯域幅とのバランスが調整されるため、スタンドアロン アプリが利用できるネットワークの帯域幅は予想以上に少ない場合があります。iPhone とペア設定された時計から Wi-Fi およびセルラー ネットワークにアクセスする場合など、ネットワーク アクセスの詳細については、こちらのガイドラインをご確認ください。

また、デベロッパー プレビューのリリースと合わせて、iOS 端末とペア設定された時計で実行されている Android Wear アプリからスマートフォン ハンドオフ フローを実行できるようになります。たとえば、OAuth やペア設定された iOS 端末でウェブページを起動する RemoteIntent などを利用できます。

Google Play ストアへのアプリのアップロード


最終デベロッパー プレビューには、ウェアラブル サポート ライブラリのアップデートが含まれています。API レベル 25 およびこのサポート ライブラリでコンパイルしたアプリは、Google Play ストアへのデプロイの準備ができていると見なされます。今回のデベロッパー プレビューのリリースでは、プレビュー ウォッチ イメージやエミュレータのアップデートはない点に注意してください。

その他の機能拡張とバグの修正


  • ナビゲーション ドロワー: フラグを反転させると、アイコンのみの単一ページ アクション ドロワーを切り替えることができます。これにより、高速で効率的なナビゲーションでアプリ内のさまざまなビューを開くことができます。
  • NFC HCE サポート: NFC ホストカード エミュレーション FEATURE_NFC_HOST_CARD_EMULATION がサポートされました。
  • ProGuard および Complication API: 新しい ProGuard 設定によって、コンプリケーション データコンテナ クラスは難読化されなくなります。この修正により、コンプリケーション データ プロバイダによって提供されるウォッチフェイスがデータにアクセスしようとする際に ClassNotFoundException が起きなくなります。

リリースへのカウントダウン


すばらしいフィードバックを送ってくださったデベロッパーの皆さん、ありがとうございます。最新のビルドとドキュメントは、g.co/wearpreview をご覧ください。2 月上旬に Android Wear 2.0 がユーザー向けに公開される前に、ぜひアプリを公開してください。私たちは、ユーザーへの公開、さらにその先に向けて作業を進めています。引き続き Android Wear デベロッパー コミュニティでのバグの送信やコメントの投稿をお願いいたします。Android Wear 2.0 アプリを見る日が待ち遠しくてたまりません!



Posted by Yoshifumi Yamaguchi - Developer Relations Team

[この記事は Sara Robinson、デベロッパー アドボケートによる Google Cloud Platform Blog の記事 "Using BigQuery and Firebase Analytics to understand your mobile app" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。]

5 月の Google I/O で、Firebase はデベロッパーのモバイルアプリ構築を支援するさまざまな製品を発表しました。新しい Firebase プラットフォームの一部である Firebase Analytics は、ユーザーが iOS アプリや Android アプリをどのように使っているかについてのデータを自動的に取得するツールで、カスタムのアプリイベントを定義することもできます。取得したデータは、Firebase コンソールのダッシュボードから参照できます。新しい Firebase プラットフォームのクラウド統合機能のうち、私が気に入っているのは、カスタムの分析を行うために Firebase Analytics の生データを Google BigQuery にエクスポートできる機能です。このカスタム分析機能は、iOS 版と Android 版のアプリのデータを集計したり、Firebase Analytics イベントで渡されるカスタム パラメータにアクセスする際に特に便利です。この強力な製品の組み合わせで何ができるのか、見てみましょう。

BigQuery エクスポートの仕組み


Firebase プロジェクトを BigQuery にリンクすると、Firebase は毎日、自動的に関連付けられた BigQuery データセットに新しい表をエクスポートします。iOS 版と Android 版の両方のアプリがある場合、Firebase は各プラットフォームのデータを別々のデータセットにエクスポートします。各表には、Firebase Analytics が取得するユーザーのアクティビティや属性データとともに、アプリで取得しているカスタム イベントが含まれています。そのため、クロスプラットフォーム アプリの 1 週間分のデータをエクスポートすると、BigQuery プロジェクトには 2 つのデータセットができ、それぞれに 7 つの表ができることになります。



データの詳細


Firebase Analytics からエクスポートされた表のスキーマは同一です。サンプルのクエリを実行してみることができるように、サンプルのユーザーデータを入れた 2 つのデータセット(iOSAndroid)を作成しました。このデータセットは、iOS と Android のクロスプラットフォーム ゲームアプリのサンプルです。各データセットには、1 週間分のアナリティクス データが入っている 7 つの表が含まれています。

次のクエリは、iOS 版アプリの 1 日分の使用状況から、いくつかの基本的なユーザー属性と端末データを返します。

SELECT
  user_dim.app_info.app_instance_id,
  user_dim.device_info.device_category,
  user_dim.device_info.user_default_language,
  user_dim.device_info.platform_version,
  user_dim.device_info.device_model,
  user_dim.geo_info.country,
  user_dim.geo_info.city,
  user_dim.app_info.app_version, 
  user_dim.app_info.app_store,
  user_dim.app_info.app_platform
FROM
  [firebase-analytics-sample-data:ios_dataset.app_events_20160601]

Firebase Analytics からエクスポートされたすべての BigQuery テーブルのスキーマは同一なので、本投稿のクエリはすべて皆様の Firebase Analytics データに対して実行できます。その場合、データセットと表の名前を自分のプロジェクトの名前で置き換えます。

スキーマには、ユーザーデータとイベントデータがあります。すべてのユーザーデータは Firebase Analytics で自動的に取得されますが、イベントデータはアプリに追加したカスタム イベントから取得されます。では、ユーザーデータとイベントデータのレコードを見てみましょう。

ユーザーデータ


ユーザー レコードには、各ユーザーの一意のアプリ インスタンス ID(スキーマの user_dim.app_info.app_instance_id)に加えて、場所、端末、アプリのバージョンなどのデータが含まれています。Firebase コンソールでは、アプリの Android と iOS のアナリティクスで別々のダッシュボードになっています。BigQuery では、プラットフォームを問わずに、クエリを実行してユーザーが世界のどこからアプリにアクセスしているかを探すことができます。次のクエリは、BigQuery のユニオン機能を活用しています。UNION ALL 演算子としてコンマを使うことができます。この表では、ユーザーによってトリガーされるひとまとまりのイベントに対して 1 行が作成されます。そのため、各ユーザーを 1 度だけ数えるように EXACT_COUNT_DISTINCT を使っています。

SELECT
  user_dim.geo_info.country as country,
  EXACT_COUNT_DISTINCT( user_dim.app_info.app_instance_id ) as users
FROM
  [firebase-analytics-sample-data:android_dataset.app_events_20160601],
  [firebase-analytics-sample-data:ios_dataset.app_events_20160601]
GROUP BY
  country
ORDER BY
  users DESC


ユーザーデータには、ユーザーベースの各セグメントを表すために定義する属性を含む user_properties レコードも含まれています。たとえば、好みの言語や所在地などがこれにあたります。Firebase Analytics は、デフォルトでいくつかのユーザー プロパティを取得します。また、25 個までの独自の属性を追加することもできます。

ユーザーの好みの言語は、デフォルトのユーザー プロパティの 1 つです。次のクエリを実行すると、両方のプラットフォームでユーザーがどの言語を使っているかを見ることができます。

SELECT
  user_dim.user_properties.value.value.string_value as language_code, 
  EXACT_COUNT_DISTINCT(user_dim.app_info.app_instance_id) as users,
FROM
  [firebase-analytics-sample-data:android_dataset.app_events_20160601],
  [firebase-analytics-sample-data:ios_dataset.app_events_20160601]
WHERE
  user_dim.user_properties.key = "language"
GROUP BY
  language_code
ORDER BY 
  users DESC


イベントデータ


Firebase Analytics を使うと、アイテムの購入やボタンのクリックなどのアプリ内のカスタム イベントを簡単に記録できます。イベントを記録する際には、イベント名と最大 25 個までのパラメータを Firebase Analytics に渡します。すると、イベントが発生した回数を自動的にトラッキングできます。次のクエリは、Android で特定の日付に発生したアプリ内の各イベントの回数を表示します。

SELECT 
  event_dim.name,
  COUNT(event_dim.name) as event_count 
FROM
  [firebase-analytics-sample-data:android_dataset.app_events_20160601]
GROUP BY 
  event_dim.name
ORDER BY 
  event_count DESC


イベントに別のタイプの値(アイテムの価格など)が関連付けられている場合、それをオプションの値パラメータとして渡し、BigQuery でその値によってフィルタすることができます。サンプル表には、spend_virtual_currency イベントがあります。次のクエリでは、プレイヤーが一度に使った仮想通貨の額が表示されます。

SELECT 
  event_dim.params.value.int_value as virtual_currency_amt,
  COUNT(*) as num_times_spent
FROM
  [firebase-analytics-sample-data:android_dataset.app_events_20160601]
WHERE
  event_dim.name = "spend_virtual_currency"
AND
  event_dim.params.key = "value"
GROUP BY
  1
ORDER BY 
  num_times_spent DESC


複雑なクエリの作成


アプリの両方のプラットフォームの特定の期間に対してクエリを実行したい場合は、どうすればよいでしょうか。Firebase Analytics データの表は日付ごとに分割されているため、BigQuery の TABLE_DATE_RANGE 関数を使います。次のクエリは、1 週間の間にアクセスしてきたユーザーの所在都市をカウントするものです。

SELECT
  user_dim.geo_info.city,
  COUNT(user_dim.geo_info.city) as city_count 
FROM
TABLE_DATE_RANGE([firebase-analytics-sample-data:android_dataset.app_events_], DATE_ADD('2016-06-07', -7, 'DAY'), CURRENT_TIMESTAMP()),
TABLE_DATE_RANGE([firebase-analytics-sample-data:ios_dataset.app_events_], DATE_ADD('2016-06-07', -7, 'DAY'), CURRENT_TIMESTAMP())
GROUP BY
  user_dim.geo_info.city
ORDER BY
  city_count DESC


さらに、1 週間の間のプラットフォーム全体でのモバイルとタブレットの使用率を比較するクエリを作成することもできます。


SELECT
  user_dim.app_info.app_platform as appPlatform,
  user_dim.device_info.device_category as deviceType,
  COUNT(user_dim.device_info.device_category) AS device_type_count FROM
TABLE_DATE_RANGE([firebase-analytics-sample-data:android_dataset.app_events_], DATE_ADD('2016-06-07', -7, 'DAY'), CURRENT_TIMESTAMP()),
TABLE_DATE_RANGE([firebase-analytics-sample-data:ios_dataset.app_events_], DATE_ADD('2016-06-07', -7, 'DAY'), CURRENT_TIMESTAMP())
GROUP BY
  1,2
ORDER BY
  device_type_count DESC


もう少し複雑なクエリを作成することもできます。プラットフォームをまたいだ直近 2 週間の一意のユーザー イベントのレポートを生成してみましょう。ここでは、PARTITION BYEXACT_COUNT_DISTINCT を使ってユーザーごとにイベントの重複を排除するとともに、ユーザー プロパティと user_dim.user_id 項目も活用しています。

SELECT 
  STRFTIME_UTC_USEC(eventTime,"%Y%m%d") as date,
  appPlatform,
  eventName,
  COUNT(*) totalEvents,
  EXACT_COUNT_DISTINCT(IF(userId IS NOT NULL, userId, fullVisitorid)) as users
FROM (
  SELECT
    fullVisitorid,
    openTimestamp,
    FORMAT_UTC_USEC(openTimestamp) firstOpenedTime,
    userIdSet,
    MAX(userIdSet) OVER(PARTITION BY fullVisitorid) userId,
    appPlatform,
    eventTimestamp,
    FORMAT_UTC_USEC(eventTimestamp) as eventTime,
    eventName
    FROM FLATTEN(
      (
        SELECT 
          user_dim.app_info.app_instance_id as fullVisitorid,
          user_dim.first_open_timestamp_micros as openTimestamp,
          user_dim.user_properties.value.value.string_value,
          IF(user_dim.user_properties.key = 'user_id',user_dim.user_properties.value.value.string_value, null) as userIdSet,
          user_dim.app_info.app_platform as appPlatform,
          event_dim.timestamp_micros as eventTimestamp,
          event_dim.name AS eventName,
          event_dim.params.key,
          event_dim.params.value.string_value
        FROM
         TABLE_DATE_RANGE([firebase-analytics-sample-data:android_dataset.app_events_], DATE_ADD('2016-06-07', -7, 'DAY'), CURRENT_TIMESTAMP()),
TABLE_DATE_RANGE([firebase-analytics-sample-data:ios_dataset.app_events_], DATE_ADD('2016-06-07', -7, 'DAY'), CURRENT_TIMESTAMP())
), user_dim.user_properties)
)
GROUP BY
  date, appPlatform, eventName


Google Analytics に同じアプリのデータがあれば、BigQuery に Google Analytics データをエクスポートし、Firebase Analytics BigQuery 表と JOIN することもできます。

アナリティクス データの視覚化


生データの BigQuery エクスポートによって、モバイルアプリのデータを使った洞察を行えるようになりました。次は、Google Data Studio を使ってデータを視覚化してみましょう。Data Studio は、BigQuery 表から直接読み出すことができます。さらに、前述のようなカスタムクエリを渡すことも可能です。Data Studio は、データ構造に応じて、時系列グラフ、棒グラフ、円グラフ、地図など、さまざまなタイプのグラフを生成できます。

最初の視覚化の例として、各プラットフォームでユーザーがアプリにアクセスする際に使っている端末のタイプを比較する棒グラフを作成してみましょう。モバイルとタブレットを比較する前述のクエリを直接 Data Studio に貼り付けると、次のグラフを生成できます。


このグラフから、iOS ユーザーはタブレットでゲームをするユーザーの方が多いことが簡単にわかります。さらに複雑な例として、両方のプラットフォームのイベント数を比較する前述のイベント レポートのクエリを使って棒グラフを作成してみます。


BigQuery プロジェクトを Data Studio に接続する詳しい手順については、こちらの投稿をご覧ください。

次のトピック


Firebase についてよく知らないという場合は、まずこちらをご覧ください。既に Firebase 上にモバイルアプリを構築している方は、Firebase プロジェクトを BigQuery にリンクするための詳しいガイドをご覧ください。質問がある場合は、BigQuery リファレンス ドキュメントを参照し、Stack Overflow で firebase-analytics タグや google-bigquery タグをつけて質問してください。また、今後の投稿で取り上げてほしいトピックがありましたら、ぜひ私にお知らせください。


Posted by Kaz Sato - Developer Relations Team

この記事は Todd Kerpelman による The Firebase Blog の記事 "Announcing Firebase 3.6 for iOS" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。



Frank van Puffelen



Todd Kerpelman
Developer Advocate


iOS デベロッパーの皆さん、こんにちは!

iOS で Firebase バージョン 3.6 が利用できるようになったことをお知らせします。バージョン 3.6 には、重要なバグの修正や iOS 10 サポートに必要な機能が含まれています。そのため、できるだけ早く pod update を実行(またはフレームワークを手動アップデート)してプロジェクトを再コンパイルすることをお勧めします。

修正内容や機能強化の完全なリストはリリースノートでご覧いただけますが、ここでは新機能について簡単に紹介しましょう。

新しい通知のサポート

Firebase Cloud Messaging は、iOS 10 の新しいユーザー通知をサポートするようになります。iOS 10 で動作するアプリの場合、userNotificationCenter:willPresentNotification: withCompletionHandler メソッドで着信する通知を処理することができます。アプリが古い application:didReceiveRemoteNotification: completionHandler メソッドしかサポートしていなくても、新しいメソッドが存在しなければ APN は古いメソッドを呼び出しますので、心配はいりません。詳しくは、アップデートされた FCM のドキュメントをご覧ください。

アプリのレビュー ガイドラインに関する注意事項

iOS 10 のアップデートに伴い、Apple は App Store のレビュー ガイドラインに多くの変更を加えました。最新版の Firebase では、新しいガイドラインに対応するように多くの変更が行われています。最も重要なのは、NSCalendarsUsageDescription NSBluetoothPeripheralUsageDescription などに対してテキストを提供するよう促す iTunes Connect エラーが表示されないようにする必要があることです。

このガイドラインに従った結果、Safari で iOS 検索のアプリ インストール広告を測定していた機能が削除されています。

Firebase Invites を利用している方は、plist ファイルで NSContactsUsageDescription を提供する必要があります。Firebase Invites はこの連絡先情報を使ってユーザーが招待状を送る可能性がある友だちのリストを作成しています。

もちろん、このプロセスは現在も継続されています。私たちは、このような変更に細心の注意を払っていますので、必要な場合にはさらにアップデートを公開します。

ログインの回避策

Xcode 8 でシミュレータのキーチェーンに値を書き込めないため Firebase Auth がエラーとなるという最近の ブログ投稿を覚えている方もいるかもしれません。この問題はまだ存在しているため、端末ではキーチェーンを利用しつつ、シミュレータでは NSUserDefaults を利用する回避策を実装しています。これによって、シミュレータで Firebase Auth の開発やテストができるようになり、全機能が利用できるようになります。

バグの修正

皆様が見つけたバグは私たちが修正します。今後も、オンライン フォームから問題や機能リクエストをお寄せください。お寄せいただいた内容は適切に対応いたします。

質問は、Firebase タグを付けて Stack Overflow でお尋ねください。または、Google グループに送信していただいても構いません。

Firebase デベロッパーの皆様、いつもありがとうございます。ぜひ、アプリのアップデートをお願いいたします!


Posted by Khanh LeViet - Developer Relations Team

[この記事は Todd Kerpelman、デベロッパー アドボケートによる The Firebase Blog の記事 "iOS 10, Xcode 8, and Swift 3, oh my!" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。]


Frank van Puffelen


Todd Kerpelman
デベロッパー アドボケート

最新かつ最高のテクノロジーを導入した環境で、自身のアプリを正しく動作させることは非常に重要です。iOS 開発について言えば、近々リリースされる iOS 10 向けにアプリをサポートしようと考えているデベロッパーの方も多いと思います。

Firebase チームでは、iOS 10 が一般公開されてすぐに、デベロッパーの皆様が自身のアプリを iOS 10 上で実行できるように準備を進めています。本記事では、Firebase CocoaPod の最新バージョン(3.5.1)における変更点を改めて紹介します。あわせて、今後予定されている変更点のうち、iOS 10 向けの開発を始めるにあたり影響がある内容についてお伝えします。

Dynamic Links、Invites、App Indexing

最新版の Firebase ライブラリでは、iOS 10 向けのディープリンク機能が新たにサポートされています。自身のアプリで Dynamic Links、Firebase Invites、App Indexing などのディープリンクを活用する機能を使用している場合は、ライブラリを最新版に更新してください。これらの機能は、(コードを変更しなくても)アプリを再ビルドするだけで正しく動作するようになります。

Firebase Analytics

Firebase SDK の最新版では、検索機能と連動した AdWords 広告経由でのアプリのインストール状況を、より正確にトラックできるようになっています。この機能は Firebase SDK のバージョン 3.3.0 で追加済みなので、既にご存じの方もいると思いますが、今回はさらに iOS 10 向けのサポートを追加しています。上述のディープリンク機能の更新と同様に、新しいライブラリを用いてコードを再ビルドすると、自動的に新機能が有効になります。

Firebase Cloud Messaging

iOS 10 では通知関連の機能が大幅に進化しており、デベロッパー側で受信したユーザー通知を処理するための新たな方法も提供されています。具体的には、 application:didReceiveRemoteNotification などの古い UIApplicationDelegate メソッドの廃止に伴い、UNUserNotificationCenterDelegate プロトコルのメソッドで通知を処理するようになっています。

ただし、お気づきの方もいるかと思いますが、Firebase SDK の最新版では、まだ古い appDelegate メソッドを使用しています。新しい UNUserNotificationCenterDelegate プロトコルのメソッドについては、近々サポートを開始できるように努めています。ライブラリを更新した際はお知らせしますので、今後の配信情報をチェックしておいてください。

Firebase Auth と Xcode 8 に関するお知らせ

最新の iOS 10(この記事を書いている時点では ベータ版 6 まで)のシミュレータでは、キーチェーンに値が書き込めず、Firebase Auth がエラーを返すという問題が発生することが判明しています。なお、この問題による実機への影響はありません。

本件は、既に Apple のバグ トラッキング システムに報告済みですので、近いうちに解決されると見込まれますが、それまではシミュレータで Firebase Auth の試験を実施すると、エラーが発生する可能性があります。この問題を回避する方法として、Auth の試験は iOS 10 が搭載された実機で実施することをお勧めします。実機をお持ちでない場合は、 アプリの Capabilities セクションで Keychain Sharing を有効にしてください。 詳しくは StackOverflow の投稿をご覧ください。

Swift 3 対応

既にお気づきの方もいるかもしれませんが、ドキュメントのサンプルコードでは、まだ Swift 2.3 を使用しています。Swift 3 は現在も開発中であるため、バージョン 3.0 が正式にリリースされてから、ドキュメント内のサンプルコードを入れ替える予定です。

もちろん現段階で、Swift 3 でサンプルの動作を試すことも可能です。最新のサンプルコードをダウンロードして、Xcode の Swift 変換ツールでサンプルを変換すると、ご利用いただけます。また、近日中にサンプルアプリ用に Swift 3 の専用ブランチを作成する予定です。そちらのブランチを GitHub からチェックアウトすれば、変換処理をしなくてもソースコードをご覧いただけます。

フィードバックをお待ちしています

今回は、ベータ版のオペレーティング システム向けにライブラリをリリースしているため、厄介な問題が発生することが見込まれます。iOS 10 の新バージョン公開に伴い、さまざまな不具合が検出された際は、できるだけ迅速に改修するよう努めてまいります。皆様の方でも iOS 10 固有の問題を発見しましたら、ぜひお知らせください。まずは Google グループ をご活用ください。


Posted by Khanh LeViet - Developer Relations Team

[この記事は David East、デベロッパー アドボケートによる Firebase Blog の記事 "The beginners guide to React Native and Firebase" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。]

David East
David East
デベロッパー アドボケート

更新情報: Firebase Realtime Database と Firebase Authentication をサポートした Firebase 3.1.0 SDK 向けにこのチュートリアルをアップデートいたしました。

Firebase チームには、多くの React ファンがいます。Firebase はアプリケーションの状態を同期し、React は状態の変化に応じてアプリケーションの UI を再描画します。この組み合わせは完璧です。

さらに、React Native があれば、JavaScript デベロッパーにとってのアプリ開発は、これまで以上に簡単 なものになります。JavaScript だけで本物のネイティブ アプリを作れるようになるからです。なんとすばらしいことでしょう。未来に住んでいるようですね。では早速始めてみましょう。

セットアップ

コードを詳しく見てみたい方は、こちらから最終版の GitHub リポジトリをチェックできます。そうでない方のために、順を追って説明します。

React Native を使ってみるのはとても簡単ですが、いくつか知っておくべきポイントがあります。既に React Native をセットアップしている場合は、このセクションをスキップしてください。

まず、Homebrew が必要になります。これは簡単にインストールできます。さらに、Node.js 4.0 以降も必要です。React Native チームは、ノードのバージョン管理に nvm を使用することを推奨しています (私もお勧めします)

以上のツールがインストールできたら、以下のコマンドを実行します。
brew install watchman
npm install -g react-native-cli

最後に、次の CLI コマンドでプロジェクトを開始します。
react-native init GroceryApp # or whatever you want

お好みのエディタでメインフォルダを開きます。
atom GroceryApp # if you’re into Atom

ビルドと実行

React Native プロジェクトをビルドするには、以下のコマンドを実行します。
react-native run-ios

シミュレータが起動し、ボイラープレート画面が表示されます。
空のアプリ
React Native はホットリロードに対応しています。index.ios.js のコードを編集して Cmd+R を押すと、即座に変更点がアップデートされます。iOS で開発を行っている方をはじめとして、デベロッパーの皆さんはこれがどんなにすばらしいことかおわかりでしょう。

ビルドのセットアップが済んだところで、Firebase を起動して実行してみます。

Firebase のセットアップ

React Native は、npm で依存性を管理しています。Firebase をインストールするには、プロジェクトのルートで次のコマンドを実行します。
npm install firebase --save

index.ios.js を開き、一番上に次の行を追加します。
import * as firebase from 'firebase';

そして、コンポーネントの直前で設定値を渡して Firebase を初期化します。
// Initialize Firebase
const firebaseConfig = {
  apiKey: "<your-api-key>",
  authDomain: "<your-auth-domain>",
  databaseURL: "<your-database-url>",
  storageBucket: "<your-storage-bucket>",,
};
const firebaseApp = firebase.initializeApp(firebaseConfig);

この const とは何でしょうか。これは、読み取り専用の値への参照です。Firebase の値を上書きすることはないので、ここで const を利用するのは筋が通っています。このキーワードを使えるのは、Node.js 4.0 以降を使用しているからです。もしエディタがエラーを表示しても、それはエディタの間違いです。

さらに、もう 1 つの ES2015 機能を使います。React.createClass() を使ってコンポーネントを定義するのではなく、クラスを利用します。

ES2015(ES6)コンポーネント

React はコンポーネントベースで動作します。つまり、アプリはルート コンポーネントから始まる単なるコンポーネントのツリーです。React 0.14 では、ES2015 クラスを使って React コンポーネントを定義できます。

index.ios.js で、React.createClass() ではなくクラスを使用するようにコンポーネントを変更してみましょう。
class GroceryApp extends Component {
  render() {
    return (
      <View style="{styles.container}">

      </View>
    );
  }
}

React.createClass() ではなく ES2015 クラスを使う理由は何でしょうか。このテーマは大きな議論となっていますが、結局これは趣味の問題だという結論になっています。

これで、アプリのシェルは完成です。次は、見栄えをよくし、もう少しきちんとしたアプリにしてみましょう。

React Native によるスタイル設定

React Native では、スタイル設定に CSS ではなく JavaScript を使用します。まったく異なる手法だと感じる方がいらっしゃるかもしれませんが、実際はそれほど異なるものではありません。スタイルを宣言するには、StyleSheet を作成します。
var styles = StyleSheet.create({
  container: {
    backgroundColor: '#f2f2f2',
    flex: 1,
  },
});

StyleSheet には、CSS のような形でスタイルを表現するいくつかのオブジェクトを含めることができます。そのスタイルは React コンポーネントで使用できます。
<View style="{styles.container}">
  I’m a container lol!
</View>

そのため、CSS のスキルが無駄になるわけではありません。React Native でスムーズにスタイル設定を行うには、CSS Flexbox を学習するとよいでしょう。

React のスタイル設定もできるようになりましたので、次はアプリのスタイルを宣言します。

スタイルの追加

styles.js という名前のファイルを作成し、このファイルのコードを追加します。記載されているのは、今回のアプリで使用するスタイルです。

React Native は CommonJS モジュールを使っていることに気づく方もいるでしょう。styles.js の最後の部分で、module.exports を使用して StyleSheet をエクスポートしています。

こうすることによって、このスタイルを require() でインポートすることができます。index.ios.js を開き、次の行を追加します。
const styles = require('./styles.js')

ファイルの下部にあるスタイル変数は忘れずに削除してください。

これでスタイルを設定できました。次に、アプリのコンポーネント構造を見てみましょう。

UI をコンポーネント階層に分割する

React について私が最も役立つと感じているアドバイスは、 UI をコンポーネント階層に分割するところから始めることです。次の図は、今回のアプリのコンポーネント階層を視覚的に表現したものです。
アプリの階層
このアプリは、5 つのコンポーネントで構成されています。
  1. GroceryApp(オレンジ): アプリ全体を含みます。
  2. StatusBar(紫): ビューのタイトルを表示します。
  3. ListView(緑): 食料品アイテムのリストを表示します。
  4. ListItem(黒): リストの個々のアイテムを表示します。
  5. ActionButton(青): リストにアイテムを追加します。

components という名前のフォルダを作成します。以上のコンポーネントは、components フォルダに格納します。ただし、GroceryApp は除きます。これは index.ios.js に含めます。

以下の各コンポーネントを components フォルダに追加してください。

ActionButton.js
'use strict';

import React, {Component} from 'react';
import ReactNative from 'react-native';
const styles = require('../styles.js')
const constants = styles.constants;
const { StyleSheet, Text, View, TouchableHighlight} = ReactNative;

class ActionButton extends Component {
  render() {
    return (
      <View style={styles.action}>
        <TouchableHighlight
          underlayColor={constants.actionColor}
          
          <Text style={styles.actionText}>{this.props.title}</Text>
        </TouchableHighlight>
      </View>
    );
  }
}

module.exports = ActionButton;

ListItem.js
import React, {Component} from 'react';
import ReactNative from 'react-native';
const styles = require('../styles.js')
const { View, TouchableHighlight, Text } = ReactNative;

class ListItem extends Component {
  render() {
    return (
      <TouchableHighlight 
        <View style={styles.li}>
          <Text style={styles.liText}>{this.props.item.title}</Text>
        </View>
      </TouchableHighlight>
    );
  }
}

module.exports = ListItem;

StatusBar.js
'use strict';
import React, {Component} from 'react';
import ReactNative from 'react-native';
const styles = require('../styles.js')
const { StyleSheet, Text, View} = ReactNative;

class StatusBar extends Component {
  render() {
    return (
      <View>
        <View style={styles.statusbar}/>
        <View style={styles.navbar}>
          <Text style={styles.navbarTitle}>{this.props.title}</Text>
        </View>
      </View>
    );
  }
}

module.exports = StatusBar;

コンポーネントを追加したら、まず動きのないアプリを作ってみましょう。

動きのないモックアップ

index.ios.js で、次のインポート文をページの最初に追加します。
import React, {Component} from 'react';
import ReactNative from 'react-native';
import * as firebase from 'firebase';
const StatusBar = require('./components/StatusBar');
const ActionButton = require('./components/ActionButton');
const ListItem = require('./components/ListItem');
const styles = require('./styles.js');

さらに、次のコード スニペットを追加します。
_renderItem(item) {
    return (
      <ListItem item="{item}"  ==""> {}} />
    );
  }

  render() {
    return (
      <View style="{styles.container}">

        <StatusBar title="Grocery List">

        <ListView datasource="{this.state.dataSource}" renderrow="{this._renderItem.bind(this)}" style="{styles.listview}/">

        <ActionButton title="Add"  ==""> {}} />

      </View>
    );
  }

render() 関数でアプリのメインビューを作成し、_renderItem() でリストの個々のアイテムを設定しています。

次に、ルート コンポーネントである GroceryApp のコンストラクタを作成します。
constructor(props) {
  super(props);
  this.state = {
    dataSource: new ListView.DataSource({
      rowHasChanged: (row1, row2) => row1 !== row2,
    })
  };
}

コンポーネントには、state という特殊なプロパティがあります。これは、アプリケーションのデータフロー全体を管理します。この点は、次のセクションで詳しく説明します。

アプリのステートに、ListView.DataSource を設定しています。これは ListView コンポーネントのデータ処理を効率的に行うクラスです。次のステップは、データの表示です。

コンポーネントにはそれぞれのライフサイクルがあり、重要なイベントで所定の関数が呼び出されます。コンポーネントが初めてレンダリングされるときには、componentDidMount() が呼び出されます。この場所で、アプリの初期状態を設定します。
componentDidMount() {
    this.setState({
      dataSource: this.state.dataSource.cloneWithRows([{ title: 'Pizza' }])
    })
  }

アプリをビルドして実行すると、次のような動きのないアプリが表示されます。

各コンポーネントは、単純にデータを表示したり、タップに対してコールバック関数を設定したりしています。

ここで理解しておくべきことは、これらのコンポーネントはステートフルではないという点です。各コンポーネントのプロパティは、ルート コンポーネントである GroceryApp によって設定されています。React を理解するには、ステートを管理する方法を学ぶ必要があります。

ステート

ステートは、ただの変化するデータです。このデータがステートと呼ばれるのは、アプリケーションの「ステート」(状態)を示しているからです。このデータが変化すると、アプリケーションの表示が変化する可能性が高いため、異なる「ステート」になると表現できます。一般的に、ステートは ToDo リストの項目や、有効 / 無効ボタンのようなものです。

ルート コンポーネントはステートのホルダーとなります。ステートの変化はルート コンポーネントから始まります。その際に、ルート コンポーネントは子コンポーネントのプロパティをアップデートします。

コンポーネントのプロパティは不変です。すなわち、更新することはできません。 では、どうやって更新できないものを変更すればよいのでしょうか。 その方法とは、componentDidMount() で見たように、setState() を呼び出してアプリケーションを再描画することです。

setState() は特別な関数です。この関数は、呼ばれるたびにアプリ全体を再描画しようとします。具体的には、子プロパティが前回のステートと異なる場合、新しい値で再描画します。

React と Firebase の相性がとてもよいのはこのためです。Firebase データベースが複数の端末間でアプリケーションのステートを同期し、React が効率的にアプリケーションのステートの変化を再描画します。

リアルタイム データベース リスナー

コンストラクタで、プロパティとして Realtime Database へのリファレンスを作成します。
this.itemsRef = firebaseApp.database().ref();

次に、GroceryApp のコンポーネントに次の関数を追加します。
listenForItems(itemsRef) {
    itemsRef.on('value', (snap) => {

      // get children as an array
      var items = [];
      snap.forEach((child) => {
        items.push({
          title: child.val().title,
          _key: child.key
        });
      });

      this.setState({
        dataSource: this.state.dataSource.cloneWithRows(items)
      });

    });
  }

この関数は、すべての食料品アイテムに対する値のリスナーを作成します。アイテムが追加、変更、削除されると、そのすべての結果が Firebase SDK から DataSnapshot 形式で渡されます。DataSnapshotforEach(child) を使い、すべての子要素に対して反復処理を行って食料品リストのアイテムを示す配列に追加します。.forEach 関数では、DataSnapshot の .key() 値から _key プロパティを生成している点に注意してください。これによって、後ほどデータ操作を行う際の処理がはるかに簡単になります。

配列を設定できたら、ステートの dataSource プロパティを dataSource.cloneWithRows(items) を使ってアップデートします。cloneWithRows() 関数は、以前に定義したものと同じ DataSource に基づいた新しい ListView.DataSource を作成する便利なメソッドです。

次に、componentDidMount() にアイテムをリッスンするコードを記述します。
componentDidMount() {
    this.listenForItems(this.itemsRef);
  }

アプリをビルドして実行すると、空のページが表示されるはずです。しかし、Firebase App Dashboard またはすばらしくクールなデータビューア Vulcan からいくつかのアイテムを追加すると、表示がリアルタイムにアップデートされることがわかります。

Vulcan

これはすばらしいことですが、「Add」ボタンも動作させる必要があります。この点は、次のセクションで対応します。

アイテムの追加

ActionButton をタップした際に、アラートをポップアップさせてユーザーがアイテムを入力できるようにします。AlertIOS API を使うと、このアラート ボックスを生成できます。

アイテムの追加
GroceryApp のコンポーネントに次の関数を追加します。
_addItem() {
    AlertIOS.prompt(
      'Add New Item',
      null,
      [
        {
          text: 'Add',
          onPress: (text) => {
            this.itemsRef.push({ title: text })
          }
        },
      ],
      'plain-text'
    );
  }

AlertIOS API は、自由に拡張したアラートを構築することができます。最初の 2 つのパラメータはシンプルで、アラート ボックスのタイトルとメッセージ(省略可能)です。この API で重要になるのは、3 つ目のパラメータです。ここで、ユーザーが利用できるボタンを指定する配列を作成します。各ボタンには、textstyleonPress コールバック関数を指定できます。最後のパラメータは入力タイプで、plain-text または secure-text を指定します。

アイテムを追加するには、ボタン配列の中にオブジェクトを作成します。このオブジェクトで、onPress コールバックを使ってアイテムを追加できます。このコールバックは、ユーザーが入力したテキストを受け取ります。このテキストを .push() に渡し、新しい子要素を /items ロケーションに作成します。

次に、render() を改訂して ActionButton の onPress プロパティを割り当てます。
<ActionButton title="Add" >
</ActionButton>

ビルドして実行し、Add ボタンをタップしてアイテムの名前を入力すると、リストがアップデートされるはずです。

すばらしいですね。しかし、完了したアイテムを削除できない食料品リストはあまり役に立ちません。

アイテムの完了

では、ユーザーがアイテムを完了できるようにしましょう。アイテムをタップするとアラート ボックスが開き、そこで「Complete」を押すと、リストから削除されるようにします。

_renderItem(item) を変更して onPress コールバックを追加します。
_renderItem(item) {

    const  => {
      AlertIOS.prompt(
        'Complete',
        null,
        [
          {text: 'Complete', onPress: (text) => this.itemsRef.child(item._key).remove()},
          {text: 'Cancel', onPress: (text) => console.log('Cancel')}
        ],
        'default'
      );
    };

    return (
      <ListItem item="{item}" >
    );
  }

アイテムを「完了」するためには、Firebase データベースからアイテムを削除しなければなりません。.child(key) を使うと、リストの特定の項目を取得することができます。onPress コールバックはクロージャなので、item パラメータを含む外側のコードにアクセスできます。ここで、先ほどの _key プロパティが役立ちます。

「Complete」がタップされた際に、item_key プロパティを使って特定の子要素を検索することができます。そして、.remove() を呼び出して Firebase データベースからアイテムを削除します。

再度ビルドして実行し、いずれかの ListItem をタップして「Complete」を選ぶと、リストからアイテムが削除されるはずです。

コードを取得してスターマークを

完全なアプリは Github からチェックアウトできます。よろしければ、ぜひスターマークをお付けください。リポジトリは自由にフォークしてください。PR をお送りいただいても構いません。

お困りの場合

何か問題がありましたら、Stackoverflow で質問してください。私たちは Firebase タグを頻繁に確認しています。もしくは、コミュニティ Slack チームにご連絡ください。


Posted by Eiji Kitamura - Developer Relations Team

[この記事は Pete Warden、ソフトウェア エンジニアによる Google Developers Blog の記事 "TensorFlow v0.9 now available with improved mobile support" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。]

TensorFlow の開発を始めた際の最優先事項は、モバイル端末のサポートでした。Translate や Maps、Google アプリのような Google のモバイルアプリは、端末上で実行されるニューラル ネットワークを使用したアプリです。私たちは、オープンソース TensorFlow の最も重要な部分はモバイルだと考えています。

TensorFlow は、リリース当初から Android で利用できました。加えて本日(*原文公開当時)、TensorFlow v0.9 は iOS でも利用できるようになり、 Raspberry Pi のサポートと新しいコンパイル オプションも追加されました。

iOS で TensorFlow をビルドするために、クロスコンパイル処理を行ういくつかのスクリプトを作成しています。そのうちの makefile は、常に利用できるわけではない Bazel を使わずに TensorFlow をビルドする際に役立ちます。
以上のことは、最新の TensorFlow ディストリビューションにすべて含まれています。詳しくは、モバイル TensorFlow ガイドや iOS サンプルAndroid サンプルのドキュメントをご覧ください。モバイル用サンプルでは、ImageNet Inception v1 classifier を使用して画像を分類することができます。
現在のモバイル用サンプルはほんの触りに過ぎません。皆様のサポートや貢献をお待ちしています。ソーシャル メディアの投稿に #tensorflow タグをつけて、皆様のプロジェクトを共有してください。

TensorFlow 0.9.0 リリースノートの完全版は、こちらからご覧いただけます。


Posted by Kazunori Sato - Google Cloud Platform