多くのユーザーが、お気に入りのウェブサイトで使う支払い情報やパスワードを Google アカウントに保存して、簡単にアクセスできるようにしています。しかし最近まで、Chrome でこういった情報にアクセスするのは必ずしも簡単とは限りませんでした。たとえば、(ようやく)ぴったりのホリデーギフトを見つけて購入手続きを始めても、そのデバイスで Chrome の同期をオンにしていない限り、Password Manager に保存したログイン認証情報や、アカウントに追加した支払い方法を使うことはできませんでした。 

昨年この点を変更し、Google アカウントの支払い方法に簡単にアクセスできるようにしました。その後も、Chrome から Google アカウントの情報に簡単かつ直感的にアクセスできるようにし、他の機能やユーザーに同じようなログイン体験を提供するための作業を懸命に進めています。そしてうれしいことに、今後の数週間から数か月間で、同期しているかどうかにかかわらず、ログインしているすべてのユーザーが支払いとパスワード管理をシームレスに利用できるようになることをお知らせします。

Android でのログインがさらに便利に

Google アカウントを最大限に活用してもらえるように、まもなく Android 版 Chrome でタップ 1 回でログインできるようになります。この機能は、同期を行っていない場合でも利用できます。Gmail などの Google のサービスにログインする場合は、1 回のタップで認証情報を再入力することなく、デバイスのいずれかの Google アカウントで Chrome にログインできるようになります。デバイスにアカウントを追加せずにログインしたい場合は、単純にダイアログを閉じることもできます。一時的なセッションでブラウジングしたい場合は、メニューからすばやくシークレット モードを開くことができます。



Android 版 Chrome による支払いが簡単に

近いうちに、新しいシングルタップ オプションを使って Android スマートフォンで Chrome にログインした場合に、Google アカウントに保存した支払い方法を自動入力できるようになります。これにより、ショッピング体験がさらに快適になります。Chrome は、カードの CVC の確認や生体認証を求め、その後に処理を継続できます。アカウントに新しいクレジット カードを保存し、すべてのデバイスで利用することもできます。アカウントにカードを保存すると、そのたびに確認メールが送信されます。カード情報は、アカウントの支払い方法のページからいつでも管理したり削除したりできます。



PC 版 Chrome によるパスワード管理が簡単に

Google アカウントに保存したパスワードにもっと柔軟にアクセスしたいというフィードバックが寄せられています。そこで、今後数か月間で、デバイスを問わず、安全かつ簡単にパスワードにアクセスして管理できるようにします。これは、同期を有効にしているかどうかにかかわらず、Google アカウントにログインするだけで可能になります。アカウントにパスワードを保存してあるサイトでは、そのパスワードを自動入力できます。また、新しくパスワードを保存する場合、Chrome はデバイスと Google アカウントのどちらに保存するかを確認します。アカウントを選択すると、すべてのデバイスからアクセスできるようになります。

この変更により、さらに多くのユーザーに Chrome のパスワード生成機能を使ってもらえるようになります。そのため、ユーザーが Chrome で管理している多くのオンライン アカウントで、強固な専用パスワードを作成できます。



以上の機能は今後数か月間で導入される予定ですので、ぜひご注目ください。いつものように、今後のアップデートについてのブログもお見逃しなく。

Reviewed by Eiji Kitamura - Developer Relations Team



Jen Looper
Developer Advocate at ProgressSW

NativeScript、Firebase、Angular 2 という強力な組み合わせを活用すれば、アプリの構築を一気に加速させることができます。クリスマス休暇の期間中は、アプリの開発をスピードアップさせて、プレゼントを贈りたいという家族のニーズに応えなければならないため、特にその点が重要になります。ちょうどよいことに、Angular 2 ベースの NativeScript アプリで Firebase を使う方法のデモを皆さんにプレゼントすることができます(以下をご覧ください 🎁)。これは、Eddy Verbruggen 氏による有名な NativeScript-Firebase プラグインのいくつかのコンポーネントを使ったものです。


このチュートリアルでは、よく使われている次の 4 つの Firebase 機能を NativeScript アプリで使用する方法を説明します。4 つの機能には、ログインとユーザー登録の機能を提供する Authentication、リアルタイムにアップデートされるデータ ストレージの Realtime Database、リモートでアプリを変更できる Remote Config、写真を保存する Storage があります。説明するにあたって、以前に Ionic で書いた Giftler アプリを書き直すことにしました。

実際のプロジェクトで作業に着手する前に、ドキュメントに目を通し、以下の前提事項について確認することをお勧めします。

  • ローカルマシンに NativeScript がインストールされており、CLI が問題なく動作していることを確認します。
  • お好みの IDE で、NativeScript と Angular の開発環境を設定します。TypeScript が必要になるので、トランスパイル プロセスが動作することを確認しておきます。Visual StudioVisual Studio CodeJetbrains 対応の IDE などで利用できる優れた NativeScript プラグインがありますが、中でも Visual Studio Code には、開発を加速させる便利なスニペットがあります。
  • Firebase アカウントにログインし、コンソールを開きます。
  • Firebase コンソールで新しいプロジェクトを作成します。ここでは、「Giftler」という名前にしました。さらに、Firebase コンソールで iOS と Android のアプリを作成します。その際に、GoogleServices-Info.plist ファイルと google-services.json ファイルをダウンロードします。後ほど必要になるので、ファイルを配置した場所は覚えておいてください。


依存モジュールのインストール

Giftler は、認証が必要な NativeScript アプリのサンプルとして作成しました。このアプリでは、ユーザーがクリスマス休暇に受け取りたいギフトを、写真や説明とともに一覧表示できます。現時点で、このアプリには iOS 版と Android 版があり、以下の機能があります。

  • ログイン、ログアウト、ユーザー登録、および「パスワードを忘れた」場合の処理の実行
  • ユーザーによるリストへのギフト項目の登録
  • ユーザーによるリストからのギフト項目の削除
  • ユーザーによるリストの各ギフト項目の編集(説明や写真の追加)
  • バックエンドですぐに変更できる Firebase の Remote Config サービスによるメッセージング

それでは、Giftler のソースコードをフォークしましょう。これは、問題なく動作している完全版のアプリです。アプリをクローンできたら、アプリを作成した際にダウンロードした、現在の Firebase 関連のアプリのファイルを置き換えます。

  • Firebase からダウンロードした google.services.json ファイルを /app/App_Resources/Android folder に配置します。
  • 同様に、Firebase からダウンロードした GoogleService-Info.plist ファイルを /app/App_Resources/iOS folder に配置します。


これらのファイルは、アプリで Firebase を初期化し、関連する外部サービスに接続するために必要です。

次に、アプリのルートにある package.json を確認します。このファイルには、アプリで使用するプラグインが含まれています。ここでは、NativeScript に関連するプラグインに注目してください。

"nativescript-angular":"1.2.0",
"nativescript-camera": "^0.0.8",
"nativescript-iqkeyboardmanager": "^1.0.1",
"nativescript-plugin-firebase": "^3.8.4",
"nativescript-theme-core": "^1.0.2",


NativeScript-Angular プラグインは、Angular と NativeScript を統合するプラグインです。Camera プラグインを使うと、少しカメラを管理しやすくなります。IQKeyboardManager は iOS 専用のプラグインで、厄介な iOS のキーボードを管理してくれます。Theme プラグインは、スキンを完全に自作しなくてもデフォルトのスタイルをアプリに追加できるすばらしいプラグインです。最後に、このアプリでもっとも重要なのが Firebase プラグインです。

以上の依存モジュールを配置して、プラグインをインストールする準備ができたら、iOS と Android のそれぞれのコードが格納された platforms フォルダを作成し、Firebase プラグインやその他の npm ベースのプラグインを初期化して、アプリを構築できるようにします。NativeScript CLI を使ってクローンしたアプリのルートに移動し、tns run ios または tns run android を実行します。これによってプラグインをビルドするルーチンが開始されます。中でも、Firebase プラグインのさまざまなパーツのインストールが始まることが確認できるはずです。インストール スクリプトが実行されると、さまざまな Firebase サービスを統合するためのコンポーネントをインストールするかどうかの確認が表示されます。ここでは、Messaging とソーシャル認証を除くすべてを選択します。ここでの大きな特徴は、firebase.nativescript.json ファイルがアプリのルートにインストールされることです。そのため、今後プラグインの新しいパーツをインストールしたい場合、このファイルを編集するだけでプラグインを再インストールできます。


ここで、tns livesync ios --watch または tns livesync android --watch を実行し、エミュレータでアプリが起動して変更が監視されることを確認すると、アプリが実行されて新しくログインする準備ができていることがわかります。ただし、ログインを行う前に、Firebase コンソールの [Authentication] タブからメール / パスワードによるログインを有効にして、Firebase がこのタイプのログインを処理できるようにする必要があります。


この裏で何が起こっているかを確認するために、少しばかり内部の仕組みを見てみましょう。Firebase にログインするには、インストールした Firebase サービスを初期化しておく必要があります。app/main.ts には、いくつか興味深い点があります。

// this import should be first in order to load some required settings (like globals and reflect-metadata)
 import { platformNativeScriptDynamic } from "nativescript-angular/platform";

 import { AppModule } from "./app.module";
 import { BackendService } from "./services/backend.service"; 
 

 import firebase = require("nativescript-plugin-firebase"); 


 firebase.init({
   //persist should be set to false as otherwise numbers aren't returned during 
 livesync
  persist: false,
  storageBucket: 'gs://giftler-f48c4.appspot.com',
  onAuthStateChanged: (data: any) => {
    console.log(JSON.stringify(data))
    if (data.loggedIn) {
      BackendService.token = data.user.uid;
    }
    else {
      BackendService.token = "";
    }
   }
 }).then(
   function (instance) {
     console.log("firebase.init done");
   },
   function (error) {
     console.log("firebase.init error: " + error);
   }
   );
 platformNativeScriptDynamic().bootstrapModule(AppModule); 


最初に、プラグインから firebase をインポートし、.init() を呼び出します。次に storageBucket プロパティを編集し、Firebase コンソールの [Storage] タブに表示されている値を貼り付けます。

これで、お使いの Firebase アカウントに合わせてアプリがカスタマイズされ、アプリで新しいユーザーの登録とログインが可能になるはずです。必要に応じて、app/login/login.component.ts ファイルの user.email と password 変数を編集して、デフォルトのログイン認証情報を [email protected] からご自身のログインとパスワードに変更することもできます。

iOS と Android のログイン画面
注: iOS では、Xcode シミュレータを使うとすぐにアプリをエミュレートできます。ただし Android では、アプリをエミュレータにインストールするために、Google Services の有効化など、追加でいくつかの手順が必要になる場合があります。

コードの構造と認証

Angular 2 のデザイン パターンでは、コードをモジュール化する必要があります。そのため、以下のコード構造に従うものとします。

—login
  1. login.component.ts
  2. login.html
  3. login.module.ts
  4. login.routes.ts
—list …

—list-detail …

—models

  1. gift.model.ts
  2. user.model.ts
  3. index.ts
—services
  1. backend.service.ts
  2. firebase.service.ts
  3. utils.service.ts
  4. index.ts
app.component.ts

app.css

app.module.ts

app.routes.ts

auth-guard.service.ts

main.ts

Firebase の認証が Angular 2 の auth-guard.service と連携する方法に注目してください。前述のように、アプリの app/main.ts で Firebase が初期化されます。その際に、onAuthStateChanged 関数が呼び出されます。

onAuthStateChanged: (data: any) => { 
    console.log(JSON.stringify(data))
    if (data.loggedIn) {
      BackendService.token = data.user.uid;
    }
    else {
      BackendService.token = "";
    }
  }

アプリが起動する際に、Firebase から返されるデータを文字列化したものをコンソールで確認してください。そのユーザーに loggedIn フラグが立っている場合、Firebase から送り返された userId を token として設定します。NativeScript アプリケーション設定モジュールを使って、この userId を保存するかつ、これから作成するデータと関連付けます。このモジュールは、localStorage のような機能を持つモジュールです。このトークンとトークンを使う認証テストは app/services/backend.service.ts ファイルで管理されており、app/auth-guard.service.ts ファイルで利用できます。auth-guard ファイルは、アプリのログインおよびログアウト状態を適切に管理する方法を提供しています。

AuthGuard クラスは、Angular Router モジュールの CanActivate インターフェースを実装しています。

export class AuthGuard implements CanActivate {
  constructor(private router:Router) { } 

  canActivate() {
    if (BackendService.isLoggedIn()) {
      return true;
    }
    else {
      this.router.navigate(["/login"]);
      return false;
    }
  }


基本的には、前述のログイン ルーチンでトークンが設定され、かつ BackendService.isLoggedIn 関数が true を返す場合、アプリでデフォルトのルートであるウィッシュリストへのナビゲーションが許可されます。しかし、それ以外の場合、ユーザーはログイン画面に戻されます。

const listRoutes:Routes = [
  { path: "", component:ListComponent, canActivate: [AuthGuard] },
];

これで、Firebase を使う NativeScript アプリを初期化できました。次は、アプリにデータを読み込み、Firebase のすばらしいリアルタイム性を活用して、アップデートされるデータベースの内容を監視する方法について学んでゆきましょう。

リストの作成とダブルチェック

ウィッシュリストのベースとなっている app/list/list.html から説明します。ここには、テキスト項目と空のリストが表示されているはずです。では、サンタさんに欲しいものを伝えてみましょう。項目がデータベースに送信され、リアルタイムにリストに追加されます。これをどうやって実現しているかを見てみましょう。

app/list/list.component.ts では、最初にギフトのリストを保持するための監視可能オブジェクトを設定しています。 public gifts$: Observable; 次に、コンポーネントの初期化の際に、データベースからリストを読み込みます。

ngOnInit(){
  this.gifts$ = this.firebaseService.getMyWishList();
}


おもしろいのは firebaseService ファイルです。この関数では、リスナーを追加して Firebase Database の Gifts コレクションの変更を監視する監視可能オブジェクト rxjs を返しています。この方法に注目してください。

getMyWishList():Observable {
   return new Observable((observer: any) => { 
       let path = 'Gifts';
         let onValueEvent = (snapshot: any) => {
           this.ngZone.run(() => {
             let results = this.handleSnapshot(snapshot.value);
             console.log(JSON.stringify(results))
              observer.next(results);
           });
         };
         firebase.addValueEventListener(onValueEvent, `/${path}`);
     }).share(); 
   }


このクエリの結果は、次に示す handleSnapshot 関数で処理されます。この関数は、ユーザーがフィルタリングしたデータを _allItems 配列に設定しています。

handleSnapshot(data: any) {
    //empty array, then refill and filter 
    this._allItems = [];
    if (data) {
      for (let id in data) {
        let result = (Object).assign({id: id}, data[id]);
        if(BackendService.token === result.UID){
          this._allItems.push(result);
        }
      }
      this.publishUpdates();
    }
    return this._allItems;
 }


最後に、publishUpdates が呼び出されます。この関数は、新しい項目が先頭に表示されるように、日付でデータを並び替えています。

publishUpdates() {
    // here, we sort must emit a *new* value (immutability!)
    this._allItems.sort(function(a, b){
         if(a.date < b.date) return -1;
         if(a.date > b.date) return 1;
       return 0;
    })
    this.items.next([...this._allItems]);
  }


監視可能オブジェクト $gifts にデータが設定されると、要素の編集や削除を行うたびにリスナーが呼ばれ、フロントエンドが適切にアップデートされます。getMyWishList メソッド内の onValueEvent 関数で ngZone が使われていることに注意してください。これによって、非同期に行われるデータのアップデートに応じて UI が適切にアップデートされます。NativeScript アプリの ngZone の概要については、こちらをご覧ください。

メッセージのリモート設定


もう 1 つの優れた Firebase サービスに「Remote Config」があります。これは、Firebase のバックエンドからアプリをアップデートできる機能です。Remote Config を使うと、アプリの機能のオン、オフを切り替えたり、UI を変更したりできます。ここでは、サンタさんからメッセージを送る機能を追加してみましょう。

app/list/list.html には、次のメッセージ ボックスがあります。 <Label class="gold card" textWrap="true" [text]="message$ | async"></Label> 監視可能オブジェクト message$ は、データリストとほぼ同じ方法で組み込まれていますが、ここではアプリが新しく初期化されるたびに変更が適用されます。

ngOnInit(){
  this.message$ = this.firebaseService.getMyMessage();
}


秘密は、次に示すサービスレイヤ(app/services/firebase.service.ts)にあります。
getMyMessage():Observable{
    return new Observable((observer:any) => {
      firebase.getRemoteConfig({ 
      developerMode: false,
      cacheExpirationSeconds: 300,
      properties: [{
      key: "message",
      default:"Happy Holidays!"
    }]
  }).then(
        function (result) {
          console.log("Fetched at " + result.lastFetch + (result.throttled ? " (throttled)" : "")); 
          for (let entry in result.properties)
            {
              observer.next(result.properties[entry]);
            }
          }
       );
     }).share();
 }



好きなだけ新しいメッセージを発行可能

注: アプリから必要のない高頻度で Remote Config の値を取得すると、Remote Config の利用が制限されてしまう場合がありますので、慎重に開発してください。

写真を撮る



このプロジェクトのおもしろいところは、選んだプレゼントの写真を撮って Firebase Storage に格納できる点でしょう。前述のように、この部分には Camera プラグインを使いました。これでハードウェアの管理が少し楽になります。最初に、app/list-detail/list-detail.component.ts の ngOnInit() メソッドでパーミッション セットを取得し、アプリがカメラデバイスにアクセスできるようにします。

ngOnInit() {
   camera.requestPermissions();
   ...
  }

ユーザーが詳細画面の [Photo] ボタンをクリックすると、イベント チェーンが始まります。最初に呼ばれるのは次のコードです。

takePhoto() {
  let options = {
            width:300,
            height:300,
            keepAspectRatio: true,
            saveToGallery: true
         };
     camera.takePicture(options)
          .then(imageAsset => {
              imageSource.fromAsset(imageAsset).then(res => {
                  this.image = res;
                  //save the source image to a file, then send that file path to firebase
                  this.saveToFile(this.image);
              })
          }).catch(function (err) {
              console.log("Error -> " + err.message);
          });
}


カメラで写真が撮影され、その写真が imageAsset として保存されて画面に表示されます。このイメージはファイルとしてローカルに保存されます。その際に、日付のタイムスタンプに従った名前が付けられます。また、今後の利用に備えて、パスも保存されます。

saveToFile(res){
  let imgsrc = res;
        this.imagePath =
this.utilsService.documentsPath(`photo-${Date.now()}.png`);
        imgsrc.saveToFile(this.imagePath, enums.ImageFormat.png); 
}


[Save] ボタンが押されると、イメージはローカルパス経由で Firebase に送信され、ストレージ モジュール内に保存されます。アプリに返される Firebase のフルパスは、/Gifts データベース コレクションに保存されます。

editGift(id: string){
  if(this.image){
    //upload the file, then save all
    this.firebaseService.uploadFile(this.imagePath).then((uploadedFile: any) => 
{
          this.uploadedImageName = uploadedFile.name;
          //get downloadURL and store it as a full path;
this.firebaseService.getDownloadUrl(this.uploadedImageName).then((downloadUrl: string) => {
this.firebaseService.editGift(id,this.description,downloadUrl).then((result:any) => { 
               alert(result)
             }, (error: any) => {
                 alert(error);
             });
           })
          }, (error: any) => {
            alert('File upload error: ' + error);
          });
        }
        else {
          //just edit the description
          this.firebaseService.editDescription(id,this.description).then((result:any) => {
               alert(result)
            }, (error: any) => {
               alert(error);
            });
          }
        }


このイベント チェーンは一見複雑そうですが、最終的に実行されるのは、Firebase サービス ファイルの中の数行です。

uploadFile(localPath: string, file?: any): Promise {
      let filename = this.utils.getFilename(localPath);
      let remotePath = `${filename}`;
      return firebase.uploadFile({
        remoteFullPath: remotePath,
        localFullPath: localPath,
        onProgress: function(status) {
            console.log("Uploaded fraction: " + status.fractionCompleted);
            console.log("Percentage complete: " + status.percentageCompleted);
        }
      });
  }
  getDownloadUrl(remoteFilePath: string): Promise {
      return firebase.getDownloadUrl({
     remoteFullPath: remoteFilePath})
      .then(
        function (url:string) {
          return url;
        },
        function (errorMessage:any) {
          console.log(errorMessage);
        });
}
editGift(id:string, description: string, imagepath: string){
    this.publishUpdates();
    return firebase.update("/Gifts/"+id+"",{
        description: description,
        imagepath: imagepath})
      .then(
        function (result:any) {
          return 'You have successfully edited this gift!';
        },
        function (errorMessage:any) {
          console.log(errorMessage);
        });
  }


最終的な結果では、ウィッシュリストに表示するギフトの写真と説明の両方がうまく取得できています。これでもうサンタさんは、カイリーのどのアイライナーを買えばいいのかわからないという言い訳はできません。強力な NativeScript と Angular を組み合わせれば、数分で iOS と Android のネイティブ アプリを作ることができます。これに Firebase を追加すれば、アプリのユーザー、イメージ、データを保存する強力な機能を利用でき、さらに端末間でリアルタイムにデータをアップデートすることも可能になります。すばらしいと思いませんか。このアプリは、次のようになります。



ここまで、充実したウィッシュリスト管理アプリの作成に向けて順調に進んできました。しかし、サンタさんに願いごとを伝える最高の方法はまだ模索中と言えるでしょう。次のステップとしては、Mailgun のメールとの統合やプッシュ通知の利用が考えられます。それまでの間、すばらしいクリスマス休暇をお過ごしください。皆さんが Firebase を利用してすてきな NativeScript アプリを作れるようにお祈りします。

NativeScript についてさらに詳しく学びたい方は、http://www.nativescript.org をご覧ください。質問がある方は、こちらから NativeScript の Slack チャンネルに参加してください。

Posted by Khanh LeViet - Developer Relations Team



Android Wear 2.0 の中核をなす機能は、ウォッチアプリをスタンドアロン アプリのように動作させ、ユーザーがメッセージに応答したり、フィットネスをトラッキングしたり、お気に入りのアプリを使えるようにする機能です。これは近くにスマートフォンがないときでも変わりません。Android Wear 2.0 の Developer Preview 4 には、今まで以上に強力なスタンドアロン アプリの構築に役立つ数々の新しい API が含まれています。

シームレス認証

Android スマートフォン、iPhone の両方のユーザーがシームレスな認証を行えるように、OAuth やワンクリック Google ログインのサポートが追加された API が新たに作成されました。Android Wear 向けの OAuth API を使うと、ユーザーが時計のボタンをタップしてスマートフォンの認証画面を開き、ウォッチアプリから直接サーバーサイドの API で認証できるようになります。Google ログインを使うと、この操作がさらに簡単になり、どのアカウントで認証するかを選択するだけで、ユーザーの認証が完了します。

アプリ内課金

有料アプリに加え、アプリ内課金のサポートが追加されています。これによって、Android Wear アプリやウォッチフェイスを収益化する方法がまた 1 つ増えることになります。ユーザーは、時計と 4 桁の Google アカウント PIN ですばやく簡単に購入時の認証を行えます。新しいゲームのレベルから新しいスタイルのウォッチ フェイスまで、ユーザーはデベロッパーの皆さんが作るものを購入できます。

デバイスをまたいだプロモーション

スタンドアロンで動作しないウォッチアプリもあります。また、時計とスマートフォンの両方のアプリがインストールされている場合に、よりよいユーザー エクスペリエンスを提供できることもあります。Google は皆さんのフィードバックを入念にチェックし、ペア設定された端末で Play Store を開いてユーザーが簡単にアプリをインストールできるように、2 つの新しい APIPlayStoreAvailabilityRemoteIntent)を追加しています。また、新しく追加された RemoteIntent API を使い、時計から操作してスマートフォンでカスタム URL を開くことができます。この操作には、追加のスマートフォン アプリやデータレイヤーは不要です。
// Check Play Store is available
int playStoreAvailabilityOnPhone =
    PlayStoreAvailability.getPlayStoreAvailabilityOnPhone(getApplicationContext());

if (playStoreAvailabilityOnPhone == PlayStoreAvailability.PLAY_STORE_ON_PHONE_AVAILABLE) {
    // To launch a web URL, setData to Uri.parse("https://g.co/wearpreview")
    Intent intent =
        new Intent(Intent.ACTION_VIEW)
            .addCategory(Intent.CATEGORY_BROWSABLE)
            .setData(Uri.parse("market://details?id=com.google.android.wearable.app"));
    // mResultReceiver is optional; it can be null.
    RemoteIntent.startRemoteActivity(this, intent, mResultReceiver);
}

スワイプで閉じる動作の復活

Android Wear 1.0 のスワイプで閉じる操作は、直感的で時間の節約になるという多くのフィードバックをいただきました。そこで、今回の Developer Preview リリースでは、以前の動作を復活させています。このリリースでスワイプで閉じる操作をサポートするために、次のプラットフォームと API の変更を行っています。
  • アクティビティでは、スワイプで閉じる操作が自動的にサポートされます。左から右にアクティビティをスワイプすると、そのアクティビティが閉じ、アプリはバックスタックをさかのぼります。
  • 新しいフラグメントとビューがサポートされます。新しく追加された SwipeDismissFrameLayout でフラグメントに含まれるビューや汎用的なビューをラップすると、ユーザーがスワイプしたときにアクティビティを終了するのではなく、バックスタックをさかのぼるなどのカスタム アクションを実装できます。
  • ハードウェア ボタンは「電源」にマッピングされます。以前は「戻る」にマッピングされていましたが、この変更によって、アプリがハードウェア ボタンをインターセプトできなくなりました。

詳しい情報は、Android Wear Preview サイトの動作の変更点セクションでご覧ください。

Android Wear 1.0 アプリとの互換性

Android Wear 2.0 対応の時計に、以前の埋め込みアプリのメカニズムを使ってパッケージ化された Android Wear アプリを配信できるようになっています。埋め込み Android Wear アプリを含むスマートフォン アプリをインストールしようとすると、埋め込みアプリをインストールするように通知されます。その際に埋め込みアプリをインストールしなかったユーザーは、Play Store の Android Wear ページにある「Apps you've used」(使用したことのあるアプリ)という特別なセクションから埋め込みアプリを探すことができます。

既存のメカニズムもサポートされますが、アプリをマルチ APK 配信メカニズムに移行すれば、多大なメリットを受けることができます。マルチ APK を使うと、アプリを Play Store の Android Wear ページで検索できます。また、ホームページで宣伝できたり、ウェブから時計にリモートでインストールできるなどのメリットもあります。そのため、マルチ APK に移行することを強くお勧めいたします。

Developer Preview 4 のその他の詳細

  • アクションとナビゲーションドロワー: ピーク動作が可能になっているため、ユーザーはリストの一番上や下までスクロールしなくても操作を行うことができます。アクション ドロワー用の新しい API である setShouldPeekOnScrollDown などを利用すると、ドロワーのピーク動作をさらに細かく制御できます。
  • WearableRecyclerView: WearableRecyclerView で曲線レイアウトが選択できるようになったため、RecyclerView を簡単に置き換えることができるようになりました。
  • コンプリケーション用の焼き付き防止アイコン: コンプリケーション データ プロバイダが、焼き付きやすい画面向けのアイコンを提供できるようになりました。通常、このような焼き付き防止アイコンは、インタラクティブ モードのアイコンのアウトラインです。画面の焼き付きを防ぐため、常に画面表示モードでウォッチ フェイスにアイコンをまったく表示しないように設定されている場合もあります。

フィードバックを歓迎します!

Android Wear 2.0 にすばらしいフィードバックの数々をお寄せいただき、ありがとうございます。g.co/wearpreview で最新のビルドやドキュメントをご覧いただき、バグの報告Android Wear Developers コミュニティへの投稿を通してフィードバックをお送りください。また、Android Wear Developer Preview 5 にもご期待ください!


Posted by Yoshifumi Yamaguchi - Developer Relations Team



Khanh LeViet
Developer Advocate


ソーシャル ログインを好んで利用するユーザーは最近特に増えてきています。Google ログインのほか、Facebook、Twitter などとのログイン連携を使うと、使用するサービスごとに新しくアカウントを作成する必要がなくなります。ユーザーにはそれぞれお気に入りのソーシャル ログイン プロバイダがありますが、アプリに各ログイン連携プロバイダを組み込んで管理するのは、多大な労力が必要です。この作業を楽にするのが Firebase Authentication です。

Firebase Authentication は、多くの有名なソーシャル ログイン プロバイダに対応しています。アプリに Firebase Authentication を組み込みさえすれば、Firebase は裏で自動的に複数のログイン連携プロバイダを管理してくれます。

しかし、ユーザーの居住国によっては、まだ Firebase がデフォルトで対応していないログイン連携プロバイダが好まれているかもしれません。たとえば、日本やアジアの国々では、多くのユーザーを持つ LINE ログインが幅広く普及しているので、そのサポートを期待する方もいらっしゃるでしょう。うれしいことに、Firebase Authentication のカスタム認証を使うと、LINE ログインをはじめとする多くのログイン連携プロバイダを簡単にサポートすることができます。

以前のブログ投稿では、ウェブと JavaScript SDK を使って Firebase Authentication がデフォルトで対応していないログイン連携に対応する方法を紹介しました。今回のブログ投稿では、iOS と Android に LINE ログインを組み込む方法を紹介しましょう。

設計の概要



ログインのフローは、次のような流れで実行されます。

ステップ 1: LINE Login SDK を使ってログインし、ユーザーの LINE アクセス トークンを取得します。

ステップ 2: LINE アクセス トークンを自分のサーバーに送信し、LINE 認証サーバーを使ってそれを検証します。トークンが有効である場合、ユーザーに対応する Firebase カスタム認証トークンを作成し、ユーザーの端末に返します。

ステップ 3: Firebase カスタム認証トークンを使って、端末から Firebase にログインします。

構築に着手する

準備

LINE ビジネス アカウントを取得して Firebase プロジェクトを準備するには、いくつかの設定作業が必要になります。
  • こちらの手順にしたがって LINE ビジネス アカウントを設定し、アプリに LINE SDK を組み込みます。
  • 次に、アプリに Firebase Authentication ライブラリが追加されていることを確認します(iOS / Android)。
  • カスタム認証トークンの生成に Firebase Server SDK を使うこともできますが、任意の JSON ウェブトークン ライブラリを使って生成することもできるため、これは必須ではありません。

LINE ログインフローの開始

LINE ログインのドキュメント(iOS / Android)を参照し、アプリに LINE SDK を組み込んで LINE ログイン フローを実装します。ユーザーのログインが成功すると、次のようにして LINE アクセス トークンを取得できます。

iOS(Objective-C)
NSString *lineAccessToken = self.lineAdapter.getLineApiClient.accessToken;


Android
LineAuthManager authManager = LineSdkContextManager.getSdkContext().getAuthManager();
final String accessToken = authManager.getAccessToken().accessToken;

次に、お好みのネットワーク通信ライブラリを使って、自分のサーバーにアクセス トークンを送信して検証します。今回のサンプルコードでは、iOS は GTM HTTP Fetcher を使い、Android は Volley を使っています。

iOS (Objective-C)
NSURL *url = [NSURL URLWithString:@"https:///verifyToken"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];
[request setValue:@"application/json" forHTTPHeaderField:@"content-type"];

NSDictionary *token = @{@"token" : lineAccessToken};
NSError *error;
NSData *requestBody = [NSJSONSerialization dataWithJSONObject:token
                                    options:kNilOptions error:&error];
[request setHTTPBody:requestBody];
GTMHTTPFetcher *fetcher = [GTMHTTPFetcher fetcherWithRequest:request];
[fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
    if (!error) {
       // レスポンスから Firebase カスタム認証トークンを抽出
       // ・・・
    }
}];


Android
HashMap<string, string=""> validationObject = new HashMap<>();
validationObject.put("token", accessToken);
Response.Listener responseListener = new Response.Listener() {
   @Override
   public void onResponse(JSONObject response) {
       // レスポンスから Firebase カスタム認証トークンを抽出
       // ・・・
   }
};
JsonObjectRequest fbTokenRequest = new JsonObjectRequest(
       Request.Method.POST,
       "https:///verifyToken",
       new JSONObject(validationObject),
       responseListener, errorListener);

NetworkSingleton.getInstance(activity).addToRequestQueue(fbTokenRequest);</string,>


LINE アクセス トークンと Firebase カスタム認証トークンの交換

LINE アクセス トークンを検証し、ユーザーに対応する Firebase カスタム認証トークンを生成するには、サーバーが必要になります。Firebase Node.js Server SDK と Express ウェブサーバーを使うと、シンプルなサーバーを構築できます。

まず、サーバーはユーザーの端末から LINE アクセス トークンを受信し、LINE Social Rest API を使ってそれを検証します。API のレスポンスで忘れずに channelId の値を確認し、アクセス トークンがアプリから発行されていることを検証してください。これは他のアプリやチャンネルのアクセス トークンを再利用してアプリにログインしようとするなりすまし攻撃を防ぐためです。

サーバー(Node.js)

app.post('/verifyToken', (req, res) => {
  if (!req.body.token) {
    return res.status(400).send('Access Token not found');
  }
  const reqToken = req.body.token;

  // アクセス トークンを検証するために LINE サーバーにリクエストを送信
  const options = {
    url: 'https://api.line.me/v1/oauth/verify',
    headers: {
      'Authorization': `Bearer ${reqToken}`
    }
  };
  request(options, (error, response, body) => {
    if (!error && response.statusCode === 200) {
      const lineObj = JSON.parse(body);
       // なりすまし攻撃を防ぐために必ずトークンの channelId を確認
      if ((typeof lineObj.mid !== 'undefined') 
               && (lineObj.channelId === myLINEChannelId)) {
        // LINE サーバーによるアクセス トークンの検証が成功
        // Firebase トークンを生成し、端末に返却
        const firebaseToken = generateFirebaseToken(lineObj.mid);

        // LINE プロファイルで Firebase ユーザー プロファイルをアップデート
        updateUserProfile(reqToken, firebaseToken, lineObj.mid, () => {
          const ret = {
            firebase_token: firebaseToken
          };
          return res.status(200).send(ret);
        });
      }
    }

    const ret = {
      error_message:'Authentication error:Cannot verify access token.'
    };
    return res.status(403).send(ret);
     
    });

  }
});


LINE アクセス トークンの検証が成功したら、Firebase Server SDK を使って Firebase カスタム認証トークンを生成し、ユーザーの端末に返します。LINE のユーザー ID は、Firebase のユーザー ID として再利用できます。

サーバー(Node.js)
function generateFirebaseToken(lineMid) {
  var firebaseUid = 'line:' + lineMid;
  var additionalClaims = {
    provider:'LINE'
  };
  return firebase.auth().createCustomToken(firebaseUid);
}

Firebase Server Java SDK を使うこともできます。

App Engine Flexible EnvironmentCloud Functions のようなソリューションを使うと、サーバーを管理する必要はなくなります。

カスタム認証トークンによる Firebase へのログイン

Firebase カスタム認証トークンを受信したら、それを使って Firebase にログインします。

iOS(Objective-C)

[[FIRAuth auth] signInWithCustomToken:firebaseToken 
             completion:^(FIRUser * _Nullable user, NSError * _Nullable error) {
        // ログイン結果の処理
        // ・・・
    }];


Android

FirebaseAuth.getInstance()
    .signInWithCustomToken(firebaseToken)
    .addOnCompleteListener(new OnCompleteListener() {
        // ログイン結果の処理
        // ・・・
    });


試してみる

サンプルコードはオープンソースです。ぜひダウンロードしてお試しください。 https://github.com/firebase/custom-auth-samples/tree/master/Line


Posted by Khanh LeViet - Developer Relations Team


Nicolas Garnier
Developer Programs Engineer
Firebase Authentication は、4 つのすぐに使える ID プロバイダをサポートしているため、Google、Facebook、Twitter、GitHub で認証を行うのはとても簡単です。たとえば、ウェブアプリで Firebase ユーザーに Google でログインしてもらうために必要なのは次のコードだけです。

var google = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(google);

ただ、その他の ID プロバイダを使って独自の Firebase アプリにログインしてもらいたい場合もあるかもしれません。たとえば、Instagram API を使ってユーザーが Instagram の写真を共有できるようにするつもりなら、Instagram はすばらしい選択肢になるでしょう。

Firebase にビルトインでサポートされていない ID プロバイダを使うことも可能ですが、それには少しばかりのコードとサーバーが必要になります。ここでは、Instagram によるログインを Firebase ウェブアプリに組み込むために必要な手順について、順に説明します。Instagram はログインに OAuth 2.0 を使っています。そのため、本投稿は LinkedIn のようなその他の OAuth 2.0 ID プロバイダによるログイン機能を組み込む際にも役立つはずです。

設計の概要

Instagram は OAuth 2.0 をサポートしています。これは、アプリの認証や Instagram のユーザー ID を含むユーザーデータにアクセスするための主な方法となります。必要になるのは、ユーザーに OAuth 2.0 認証コードのフローを実行してもらい、アプリへのアクセス権を付与することです。OAuth 2.0 のフローは、次のような流れで実行されます。

まず、ユーザーを Instagram の認証エンドポイントにリダイレクトする必要があります。エンドポイントでは、初めてアプリにアクセス権を付与する際に、ユーザーに同意を求める画面が表示されます。これは、ポップアップ ウィンドウで実現されています。

アプリの認証が完了すると、ユーザーは認証コードとともに元のドメインにリダイレクトされます。Instagram アプリの認証情報を使うと、サーバー側で認証コードアクセス トークンと交換できます。Instagram では、認証コードを交換する過程でユーザー ID も返されます(LinkedIn などの他の OAuth 2.0 プロバイダでは、追加のリクエストが必要になる場合もあります)。

Instagram のユーザー情報を取得すると、サーバーで Firebase のカスタム認証トークンを作成できるようになります。ユーザーは、このトークンと signInWithCustomToken メソッドを使ってウェブアプリで Firebase にログインできます。

また、クライアント上で Firebase のプロフィールをアップデートできるように、表示名や写真の URL などの Instagram から取得したユーザー プロフィール情報も渡しています。 - 注: Instagram は、ユーザーのメールアドレスは提供していません。そのため、メールアドレスなしの Firebase アカウントができることになりますが、このこと自体には特に問題はありません。以上が完了すると、ポップアップが閉じます。これで、ユーザーは Instagram アカウントのプロフィール データつきで Firebase にログインできました。

構築に着手する

では、もう少し詳細に踏み込み、重要な部分の実装方法を見てみましょう。今回は、バックエンドを Node.js で記述します。

Instagram にアプリを登録する

ウェブアプリには、Instagram 認証フローを開始するボタンが必要になります。その前に、OAuth 2.0 に必要なアプリの認証情報を取得できるよう、まず Instagram デベロッパー コンソールにアプリケーションを登録する必要があります。

Instagram アプリの設定で、http://localhost:8080/instagram-callback(テスト用)と https:///instagram-callback(本番用ドメイン)を有効なリダイレクト URI としてホワイトリスト登録しておきます。次に、Instagram クライアント IDクライアント シークレットをメモします。後でこれが必要になります。

アプリを登録し、コールバック URL をホワイトリストに登録すると、クライアント ID とクライアント シークレットが返されます。この流れは、どの OAuth 2.0 プロバイダでも必要となる典型的な手順です。

Instagram の OAuth 2.0 を設定する

サーバーでは、OAuth 2.0 プロトコルの詳細を隠蔽してくれる simple-oauth2 パッケージを使います。これを設定するためには、Instagram クライアント ID とクライアント シークレット、Instagram の OAuth 2.0 トークンと認証エンドポイントなど、いくつかの値を設定する必要があります。Instagram に対して使う必要があるのは、次の値です。

// Instagram OAuth 2 の設定
const credentials = {
 client: {
   id:YOUR_INSTAGRAM_CLIENT_ID, // 要変更
   secret:YOUR_INSTAGRAM_CLIENT_SECRET, // 要変更
 },
 auth: {
   tokenHost: 'https://api.instagram.com',
   tokenPath: '/oauth/access_token'
 }
};
const oauth2 = require('simple-oauth2').create(credentials);

Instagram 認証フローを開始する

ユーザーを Instagram の同意画面にリダイレクトする URL ハンドラをサーバーに追加します。その際に、Instagram 認証フローを完了したときにユーザーがリダイレクトされて戻ってくる場所となるリダイレクト URI を提供する必要があります。今回は、/instagram-callback をコールバック ハンドラのパスに使用します。

app.get('/redirect', (req, res) => {
  // ランダムな状態検証 Cookie を生成
  const state = req.cookies.state || crypto.randomBytes(20).toString('hex');
  // localhost で安全でない Cookie を許可
  const secureCookie = req.get('host').indexOf('localhost:') !== 0;
  res.cookie('state', state.toString(), {maxAge: 3600000, secure: secureCookie, httpOnly: true});
  const redirectUri = oauth2.authorizationCode.authorizeURL({
    redirect_uri: `${req.protocol}://${req.get('host')}/instagram-callback`,
    scope: 'basic',
    state: state
  });
  res.redirect(redirectUri);
});

また、セッション固定攻撃を避けるため、OAuth リクエストの state パラメータでランダムな文字列を渡し、それを HTTP Cookie として保存しています。これによって、戻された state パラメータと Cookie に保存されている値を比較することができ、アプリがフローを開始したことを確認できます。

クライアントでは、ポップアップを表示するボタンとして、次のようなコードを書きます。

function onSignInButtonClick() {
  // ポップアップで Auth フローをオープン
  window.open('/redirect', 'firebaseAuth', 'height=315,width=400');
};

ユーザーがログインボタンをクリックすると、ポップアップがオープンし、ユーザーが Instagram の同意画面にリダイレクトされます。

同意したユーザーには URL の code クエリ パラメータに認証コードが渡され、先ほど渡した state の値と合わせて、/instagram-callback URL ハンドラにリダイレクトされます。

アクセス トークン用の認証コードの交換

ユーザーがコールバック URL にリダイレクトされた際には、以下の処理を行います。
app.get('/instagram-callback',(req, res) => {
  // state Cookie を受け取ったことを確認
  if (!req.cookies.state) {
    res.status(400).send('State cookie not set or expired.Maybe you took too long to authorize.Please try again.');
  // state Cookie が state パラメータと一致することを確認
  } else if (req.cookies.state !== req.query.state) {
    res.status(400).send('State validation failed');
  }

  // アクセス トークン用に認証コードを交換
  oauth2.authorizationCode.getToken({
    code: req.query.code,
    redirect_uri: `${req.protocol}://${req.get('host')}/instagram-callback`
  }).then(results => {
    // Instagram アクセス トークンとユーザー ID の取得が完了
    const accessToken = results.access_token;
    const instagramUserID = results.user.id;
    const profilePic = results.user.profile_picture;
    const userName = results.user.full_name;

    // ...

  });
});

これでこの実装での OAuth 2.0 固有部分は完成です。以降は、ほぼ Firebase に固有の部分です。

次は、Firebase カスタム認証トークンを作成します。そのカスタム認証トークンを使ってログインを実行し、Firebase のユーザー プロフィールをアップデート(詳細は後述)する HTML ページを提供します。

app.get('/instagram-callback', (req, res) => {

    // ...

  }).then(results => {
    // Instagram アクセス トークンとユーザー ID の取得が完了
    const accessToken = results.access_token;
    const instagramUserID = results.user.id;
    const profilePic = results.user.profile_picture;
    const userName = results.user.full_name;
      
    // Firebase カスタム認証トークンの作成
    const firebaseToken = createFirebaseToken(instagramUserID);

    // ログインを実行し、ユーザー プロフィールをアップデートする HTML ページの提供
    res.send(
        signInFirebaseTemplate(firebaseToken, userName, profilePic, accessToken)));
  });
});

カスタム認証トークンの作成

Firebase カスタム認証トークンを作成するには、Firebase にサービス アカウント認証情報を設定する必要があります。これは、このようなトークンを生成する際に必要となる管理権限を付与するために必要になります。サービス アカウント認証情報ファイルは、service-account.json として保存してください。

const firebase = require('firebase');
const serviceAccount = require('./service-account.json');
firebase.initializeApp({
  serviceAccount: serviceAccount
});

カスタム認証トークンの作成はシンプルです。Instagram のユーザー ID に基づいて uid を選択するだけで構いません。

function createFirebaseToken(instagramID) {
  // ユーザーに割り当てる uid
  const uid = `instagram:${instagramID}`;

  // カスタム トークンの作成
  return firebase.auth().createCustomToken(uid);
}

注: サービス アカウント認証情報は安全に保管する必要があるため、カスタム トークンの作成は必ずサーバー側で行います。

カスタム トークンを作成した後は、それをクライアントに渡して Firebase にログインします。

カスタム トークンによるログイン

この時点で、サーバーはポップアップ ウィンドウ内で実行される HTML ページを提供し、以下の処理を行います。

ここでポイントとなるのは、プロフィールをアップデートする際にデフォルトの Firebase アプリを使うのではなく、一時的な Firebase App インスタンスを使っている点です。これによって、ユーザー プロフィールがアップデートされる前にメインページの Auth リスナーが呼ばれることを防いでいます。

app.get('/instagram-callback', (req, res) => {

    // ...

    // ログインを実行し、ユーザー プロフィールをアップデートする HTML ページの提供
    res.send(
        signInFirebaseTemplate(firebaseToken, userName, profilePic, accessToken)));
  });
});

function signInFirebaseTemplate(token, displayName, photoURL, instagramAccessToken) {
 return `
   <script src="https://www.gstatic.com/firebasejs/3.4.0/firebase.js"></script>
   <script src="promise.min.js"></script><!-- Promise Polyfill for older browsers -->
   <script>
     var token = '${token}';
     var config = {
       apiKey:MY_FIREBASE_API_KEY, // 要変更
       databaseURL:MY_DATABASE_URL // 要変更
     };
     // 一時 Firebase アプリにログインしてプロフィールをアップデート
     var tempApp = firebase.initializeApp(config, '_temp_');
     tempApp.auth().signInWithCustomToken(token).then(function(user) {
    
       // Realtime Database に Instagram API アクセス トークンを保存
       const tasks = [tempApp.database().ref('/instagramAccessToken/' + user.uid)
           .set('${instagramAccessToken}')];
  
       // 必要に応じて displayname と photoURL をアップデート
       if ('${displayName}' !== user.displayName || '${photoURL}' !== user.photoURL) {
         tasks.push(user.updateProfile({displayName: '${displayName}', photoURL: '${photoURL}'}));
       }
  
       // 以上のタスクの完了を待機
       return Promise.all(tasks).then(function() {
         // 一時 Firebase アプリを削除し、デフォルト Firebase アプリにログインし、ポップアップをクローズ
         var defaultApp = firebase.initializeApp(config);
         Promise.all([
             defaultApp.auth().signInWithCustomToken(token),
             tempApp.delete()]).then(function() {
           window.close(); // 完了!ポップアップをクローズ
         });
       });
     });
   </script>`;
}

ポップアップ内でユーザーがデフォルト Firebase アプリにログインすると、認証状態リスナーがメインページを起動し(Firebase では、すべてのタブで認証状態が共有されます)、それですべて完了です。ユーザー プロフィール情報を表示したり、Realtime Database や Firebase Storage を使ったりすることができます。

試してみる

自由に試していてだけるデモアプリを作成しています。https://instagram-auth.appspot.com/

サンプルはオープンソースです。ご自由に Github のリソースをご覧ください。 https://github.com/firebase/custom-auth-samples

Android と iOS への対応

この記事で紹介したコードはウェブアプリ用です。Instagram 認証を Android や iOS アプリに追加するテクニックはいくつかあります。この投稿では紹介できませんが、今後にご期待ください。

これで完了

他の ID プロバイダ用のサンプルを探している場合や、それを組み込む際に問題が発生している場合は、コメントや GitHub リポジトリの問題点でお知らせください。喜んでお手伝いいたします。


Posted by Khanh LeViet - Developer Relations Team
Share on Twitter Share on Facebook






Laurence Moroney
デベロッパー アドボケート


多くのデベロッパーにとって、アプリ用認証システムの構築は、税金を払うことのように感じるものです。どちらもわかりにくく、行わざるを得ないタスクで、うまく対応しないととんでもない結果になる可能性があります。税金を払うために会社を始める人は誰もいないように、すばらしいログイン システムを作るためだけにアプリを開発する人もいません。どちらも避けることのできない代償であるように見えます。

今なら、少なくとも「認証税」からは逃れることができます。Firebase Authentication の力を借りれば、認証システムを完全に Firebase にアウトソースし、優れたアプリを構築することに集中できます。ユーザーが簡単にログインできるようになるだけでなく、独自に認証システムを実装する際に求められる、複雑な処理を理解する必要もなくなります。簡単に使い始めることができ、ユーザーができるだけ戸惑わないようなデザインとなっているユーザー エクスペリエンス(UX)コンポーネントもオプションで提供されています。また、オープン スタンダードを基にして構築されており、Google のインフラによって支えられています。




Firebase Authentication の実装は、比較的簡単に早く済みます。広く使われているログイン方法(Facebook、Google、Twitter、メールとパスワードなど)の中から提供したいものを Firebase コンソールから選択し、Firebase SDK をアプリに追加するだけで、アプリはRealtime DatabaseFirebase Storage独自のカスタム バックエンドのいずれかと安全に接続できるようになります。すでに認証システムをお持ちの方は、Firebase Authentication を別の Firebase 機能へのブリッジとして使用することもできます。

Firebase Authentication にはオープンソース UI ライブラリも含まれており、ユーザーに優れたエクスペリエンスを提供する際に欠かせない、さまざまな認証フローを効率的に構築できます。Firebase Authentication の UI には、パスワードのリセット機能、アカウントのリンク機能、複数のログイン方法がある場合に認知的負荷を減らすログイン時のヒント機能などがすべて組み込まれています。こうしたフローは、Google や YouTube、Android でログインやサインアップのプロセスを最適化するための長年の UX リサーチに基づいています。Firebase Authentication には、多くのアプリでログイン コンバージョンを大幅に改善することにつながった Android の Smart Lock for Passwords も含まれています。Firebase UI はオープンソースなので、インターフェースは完全にカスタマイズできます。どんなアプリに組み込んでも自然に見えます。必要に応じて、クライアント API を使って一から独自の UI を作成することもできます。

さらに、Firebase Authentication はオープン性とセキュリティを中核に据えて構築されており、セキュリティ、相互運用性、移植性を持つように設計された業界標準である OAuth 2.0 と OpenID Connect を活用しています。Firebase Authentication チームのメンバーは、このようなプロトコルの設計にも携わっており、その経験を基にして ID トークン、取り消し可能なセッション、ネイティブ アプリの偽装対策といった最新のセキュリティ手法を生み出しています。それによってアプリが使いやすくなるとともに、多くの一般的なセキュリティの問題も回避できます。また、コードは Google Security チームによる独立したレビューを受けており、サービスは Google のインフラで守られています。

Fabulous がログインを短時間で実装するために Firebase Authentication を使用



Fabulous は、ログイン システムを強化するために Firebase Authentication を使用しています。デューク大学先進後知恵研究センターの研究から生まれたこのアプリは、不適切な行動を慎み、健康的な習慣を身に付けるための取り組みを始め、最終的にはユーザーが健全に幸福な暮らしを送ることを支援することを目的としています。

Fabulous のデベロッパーは、アップデートを最低限に抑え、エンドユーザーの負担を軽くする簡単な初回起動フローを実装したいと考えました。また、サインアップする前にアプリを試せるよう、匿名オプションも設けたいと考えました。さらに、複数のログイン方法をサポートし、ユーザーのログインフローとアプリのルック アンド フィールに一貫性を持たせるオプションも求めていました。

「たった半日で認証を実装することができました。以前は、独自のソリューションの作成には何週間もかかり、プロバイダの API に変更が発生するたびにアップデートしなければなりませんでした」- Amine Laadhari, Fabulous CTO

Malang Studio が Firebase Authentication で商品化までの時間を月単位で短縮



Chu-Day(AndroidiOS に対応)は、カップルが重要な日を忘れないようにするためのアプリケーションです。このアプリは、キャラクター中心のゲーム型ライフスタイル アプリケーションを開発している韓国企業 Malang Studio が作成しました。

一般的に、カウントダウンや記念日関係のアプリはユーザーのログインを要求しません。Malang Studio は、カップルをつないで特別な記念日をともにカウントダウンできるようにすることで、Chu-day を特別なアプリにして差別化を図りたいと考えました。しかしこれにはログイン機能が必要で、ユーザーの脱落を防ぐシームレスなログイン プロセスも必要でした。

Malang Studio は、Facebook や Google のログインを利用することで、 1 日で初回起動フローをアプリに組み込むことができました。サーバー側の開発やデータベースについて考える必要はなく、Firebase User Management Console を活用し、ログイン実装の開発やテスト、ユーザーの管理を行うこともできました。

「Firebase Authentication は最低限の設定しか必要としないので、短時間で簡単にソーシャル アカウントへのサインアップが実装できました。コンソールで提供されるユーザー管理機能もすばらしく、簡単に認証システムを実装できました」- Marc Yeongho Kim, Malang Studio CEO 兼 創立者

Firebase Authentication の詳細については、デベロッパー サイトと Google I/O 2016 のセッション「Best practices for a great sign-in experience」をご覧ください。


Posted by Yoshifumi Yamaguchi - Developer Relations Team
Share on Twitter Share on Facebook


こんにちは。最近、Android の Google アカウントに関する質問がいくつか寄せられています。そこで、Google が勧めるベスト プラクティスのいくつかを記事にまとめて紹介いたします。今回は、Google Play 開発者サービスの統合によって簡単に実現できる Android ベースの認証に焦点を当てます。では、始めましょう。

固有の識別子

混乱がよく生じるのが、デベロッパーがアカウント名(E メール アドレス)を Google アカウントのプライマリー キーに使用しているケースです。たとえば、ユーザーのログインに GoogleApiClient を使用しているとき、デベロッパーは、登録されている GoogleApiClient.ConnectedCallbacks リスナーに対する onConnected コールバックの中で、下に示すようなコードを使っている場合があります。

[エラーが生じやすい擬似コード]
String accountName = Plus.AccountApi.getAccountName(mGoogleApiClient);
// createLocalAccount() はアプリのローカル ストレージ ストラテジーに固有
createLocalAccount(accountName);

表示やキャッシュのために E メールアドレスを保存することに問題はありませんが、ユーザーは、Google アカウントで自身のプライマリー E メール アドレスを変更する可能性があります。そういったことは様々なタイプのアカウントで起きますが、最も頻繁に発生するのが Google Apps For Work アカウントです。

では、デベロッパーはどうしたらよいのでしょうか。Google アカウントに関連付けられているアプリのデータをキーにするときは、アカウント名ではなく、Google アカウント ID を使用します。つまり、たいていのアプリでは、アカウント ID を保存して、onConnected コールバックが呼び出されるたびに、その値を比較するだけでよく、これによって、そのデータが現在ログインしているユーザーとローカルに合致しているかを確認します。API では、アカウント ID をアカウント名から取得できるメソッドを提供しています。参考用に、スニペット例を示します。

[Google Play 開発者サービス 6.1+]
String accountName = Plus.AccountApi.getAccountName(mGoogleApiClient);
String accountID = GoogleAuthUtil.getAccountId(accountName);
createLocalAccount(accountID);
[Google Play 開発者サービスの以前のバージョン(クライアントをアップグレードしてください)]
Person currentUser = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient);
String accountID = currentUser.getID();
createLocalAccount(accountID);

こうすることで、ローカルデータは Google アカウント ID と照合されることになります。アカウント ID は ユーザーが E メールアドレスを変更した後でも変わらない固有の識別子です。

よって、上述のケースでは、データが ID をキーとしていれば、ユーザーが E メールアドレスを変更したとしても心配する必要はないのです。ユーザーが再びログインするときも、同じ ID を取得しますので、皆さんの側で何らかのデータ処理をする必要はありません。

複数アカウント

アプリが複数のアカウントによる同時接続をサポートしている場合(たとえば、下に示す Gmail ユーザー インターフェースのようなケース)、GoogleApiClients 構築時には、setAccountNameGoogleApiClient.Builder に対して呼び出します。このとき、アプリ内にそのアカウント名と Google アカウント ID を保存する必要があります。しかし、保存したアカウント名は、ユーザーがプライマリー E メール アドレスを変更すると、違ってしまうことになります。これに対処する最も簡単な方法は、ユーザーに再ログインを促すことです。そしてログイン後に、onConnected がコールされたときにアカウント名を更新します。ログインのたびに、こういったコードを使ってアカウント ID を比較し、そのアカウント ID に対してローカルに保存されている E メールアドレスを更新します。

[Google Play 開発者サービス 6.1+]
String accountName = Plus.AccountApi.getAccountName(mGoogleApiClient);
String accountID = GoogleAuthUtil.getAccountId(accountName);
// isExistingLocalAccount(), createLocalAccount(), 
// getLocalDataAccountName()、および updateLocalAccountName() は、
// すべて、アプリのローカル ストレージ ストラテジーに固有のもの
boolean existingLocalAccountData = isExistingLocalAccount(accountID);
if (!existingLocalAccountData) {
    // 新たなログイン
    createLocalAccount(accountID, accountName);
} else {
    // この Google アカウントに関する既存のローカルデータ
    String cachedAccountName = getLocalDataAccountName(accountID);    
    if (!cachedAccountName.equals(accountName)) {
        updateLocalAccountName(accountID, accountName);
    }
}

このシナリオからは、すべてのデータをアプリに保存するのにアカウント ID を使用することの重要性が分かります。

オンライン データ

上記のベスト プラクティスは、アプリのウェブサーバーに Google アカウントのデータを保存する際にも当てはまります。データをこの方法でサーバーに保存し、E メール アドレスをプライマリー キーとして扱っている場合、

ID [プライマリー キー] フィールド 1 フィールド 2 フィールド 3
[email protected] 値 1 値 2 値 3

プライマリー キーを Google アカウント ID とする下記のモデルに移行する必要があります。

ID [プライマリー キー] Email フィールド 1 フィールド 2 フィールド 3
108759069548186989918 [email protected] 値 1 値 2 値 3

ウェブ サーバーから Google API コールを行わない場合は、上述の複数アカウントのサンプルコードで参照している updateLocalAccountName メソッドを実装する場合、プライマリー E メールアドレス変更をウェブ サーバーに通知するのは、Android 向けアプリケーションに任せることができるかもしれません。ウェブ サーバーから Google API のコールを行う場合は、おそらくそれはクロス クライアント認証を使って実装したものなので、ウェブ サーバー上の OAuth2 クライアント ライブラリまたは REST エンドポイントを介して変更を検出することもできます。

まとめ

アプリで Google アカウント認証を使用するとき、ユーザーのデータを識別するには、アカウント名ではなくアカウント IDを使うのがベストな方法です。この記事では、アプリを強化するために変更作業が必要となる 3 つのケースを紹介しました。Google for Work の利用が増加しているなか、ユーザーが E メール アドレスを変更しても、アカウント ID  は同じまま維持するケースが増えてくると予想されます。よって、デベロッパーの皆さんには、できるだけ早急にコードの更新計画を立てることをお勧めいたします。


Posted by Yuichi Araki

Share on Twitter Share on Facebook