[PhoneGap/Cordova] InAppBrowserを用いてDatabase.comの認証をする方法

※本サンプルはiOSで実行していますが、Androidについても似たような方法で出来ると思います。

# Database.comとは
Database.comはsalesforce社が提供している、クラウドのデータベースサービスです。基本有料のサービスですが、会員登録することで制限つきで利用することができます。
ここではPhoneGapからDatabase.comに接続し、利用する方法を紹介します。
InAppBrowserの使い方を知りたい、という方にも参考になるかもしれません。

# サンプルアプリ
PhoneGapからDatabase.comへアクセスする方法は、[Adobe Developer Connection](http://www.adobe.com/jp/devnet/phonegap/articles/phonegap-apps-powered-by-developercom.html)でも公開されています。
またここで紹介されているソースコードは、[GitHub](https://github.com/triceam/Database.Com-PhoneGap-Sample)上でも公開されています。
ところがサンプルはInAppBrowserではなく、**ChildBrowser**と呼ばれるものを利用しています。

残念なことに、**ChildBrowserはすでにObsolateとされていて、InAppBrowserを使うことが推奨されている**ようです。
しかもInAppBrowserを使ったサンプルはほとんどなく、困っている方も多いと思います。
そこで、Adobeが提供しているサンプルを改造して、ChildBrowserをInAppBrowserで置き換えて同様の動作を実現する方法を紹介したいと思います。

PhoneGapのプロジェクトを立ち上げる方法については、[Qiitaによくまとまっている投稿](http://qiita.com/yudaifuijta0121/items/173068cc713568e92bb7)があるので、参考にしてみてください。
またDatabase.comの登録方法や、作成するデータベースの設定などについては[Adobe Developer Connection](http://www.adobe.com/jp/devnet/phonegap/articles/phonegap-apps-powered-by-developercom.html)を参照してください。

# InAppBrowserのインストール
InAppBrowserは初期状態ではインストールされていないので、以下のコマンドを用いてインストールします。

```shell-session:install_InAppBrowser.sh
$ cordova plugin add org.apache.cordova.inappbrowser
```

インストールした後にビルドを行った場合、エラーで異常終了してしまうことがあります。
その時は一度、以下のコマンドを用いてプロジェクトをクリーンアップしてから再度ビルドを行いましょう。

```shell-session:cleanup_env.sh
$ cordova platform rm ios
```

#config.xmlの書き換え

InAppBrowserを有効化するために、wwwディレクトリの1つ上のディレクトリにあるconfig.xmlを開き、**\<widget\>\</widget\>**の間に以下を追加します。

```xml:config.xml
<feature name="InAppBrowser">
  <param name="ios-package" value="CDVInAppBrowser" />
</feature>
```

# InAppBrowserを用いてDatabase.comにアクセスするソースコード

InAppBrowserを用いてDatabase.comにアクセスするJavascriptのコードを以下に示します。
簡単なソースの説明はコメントとして書いています。
[Adobeのサンプル]((https://github.com/triceam/Database.Com-PhoneGap-Sample))をそのまま使う場合は、**salesforceWrapper.js**をこのコードで置き換えれば良いです。

```js:salesforceWrapper.js
function SalesforceWrapper()
{
    // 認証パラメータ
    this.loginUrl = 'https://login.salesforce.com/';
    this.clientId = 'YOUR_KEY_HERE';    // Database.comで取得したAPI key
    this.redirectUri = 'https://login.salesforce.com/services/oauth2/success';

    // クラス変数
    this.cb = undefined;      // InAppBrowser
    this.client = undefined;  // forceTk

    this.init();
}

SalesforceWrapper.prototype.init = function() {
    this.client = new forcetk.Client(this.clientId, this.loginUrl);
};

SalesforceWrapper.prototype.login = function (successCallback) {
    // 認証画面の表示
    var url = this.getAuthorizeURL(this.loginUrl, this.clientId, this.redirectUri);
    this.cb = window.open(url, "_blank", 'location=no,toolbar=no,clearsessioncache=yes');

    this.loginSuccess = successCallback;

    // 画面遷移した場合に呼び出される関数の登録
    var self = this;
    self.cb.addEventListener('loadstop', function(e) {
            var loc = e.url;
            // 認証が通った場合の処理
            if (loc.indexOf(self.redirectUri) != -1){
                self.cb.close();    // 認証画面を閉じる
                self.sessionCallback(unescape(loc));
            }
        });
};

// 認証用のURLを取得
SalesforceWrapper.prototype.getAuthorizeURL = function (loginUrl, clientId, redirectUri) {
       return loginUrl + 'services/oauth2/authorize?' + '&response_type=token&client_id=' + encodeURIComponent(clientId) + '&redirect_uri=' + encodeURIComponent(redirectUri);
};

// 認証が通り認証画面が閉じた後に実行される関数
SalesforceWrapper.prototype.sessionCallback = function (loc) {
    var oauthResponse = {};
    var fragment = loc.split("#")[1];

    if (fragment) {
        var nvps = fragment.split('&');
        for (var nvp in nvps) {
            var parts = nvps[nvp].split('=');
            oauthResponse[parts[0]] = unescape(parts[1]);
        }
    }

    if (typeof oauthResponse === 'undefined' || typeof oauthResponse['access_token'] === 'undefined') {
        console.log("error");
    }
    else {
        this.client.setSessionToken(oauthResponse.access_token, null, oauthResponse.instance_url);
        if (this.loginSuccess){
            this.loginSuccess();
        }
    }
    this.loginSuccess = undefined;
};

```

# 使い方

上であげたソースコードの使い方を示します。

HTML側には以下を追加します。

```html:salesforce_sample.html
<script type="text/javascript" src="js/salesforceWrapper.js"></script>
```
Javascriptからは以下のように呼び出します。

```js:salesforce_sample.js
var sfw;

sfw = new SalesforceWrapper(); // SalesforceWrapperの初期化
sfw.login( successCallback );  // Salesforceへログイン

// ログインが成功したときに呼び出される関数
function successCallback()
{
   // ログインが成功したときの処理など
}
```

# 改造後のサンプルアプリ

[Adobeのサンプルアプリ](https://github.com/nutti/Database.Com-PhoneGap-Sample)についてInAppBrowserで使えるように私が編集したものを、[GitHub](https://github.com/nutti/Database.Com-PhoneGap-Sample)で公開しています。
よろしければ使ってみてください。

# サンプルアプリの実行

さて準備が整ったところで、サンプルアプリを実行してみましょう。以下のコマンドを用いてiOSシミュレータを起動させます。

```shell-session:run_ios_sim.sh
$ cordova run ios
```

最初にログイン画面が出るので、**Login**を押した後で表示される認証画面に、Database.comに登録したユーザー名とパスワードを入力してログインします。

![1_small.jpg](https://qiita-image-store.s3.amazonaws.com/0/38888/e59a3fd4-759c-9839-1fe5-2f1f12e9002a.jpeg)　　　　　　![2_small.jpg](https://qiita-image-store.s3.amazonaws.com/0/38888/42342b5f-570f-774b-54ca-13767c0ebfdc.jpeg)

ログインに成功すると二つのボタンが現れますので、**Add New Record**を押して表示されるフォームに適当な情報を入力した後、**Save**を押して登録してみましょう。

![4_small.jpg](https://qiita-image-store.s3.amazonaws.com/0/38888/704982ec-e10a-e289-ccf9-a4f6cff8242a.jpeg)　　　　　　![3_small.jpg](https://qiita-image-store.s3.amazonaws.com/0/38888/ff2c4f9f-6ea4-8267-f9e6-319a089c6e76.jpeg)

登録が完了したら、**Query My Records**を押して登録された情報がきちんと登録されているか確認します。
先ほど登録した情報が表示されていれば、登録に成功しています。

![5_small.jpg](https://qiita-image-store.s3.amazonaws.com/0/38888/16f595aa-b461-9d87-7291-1d4386168db4.jpeg)

# 参考情報
* [Adobe Developer Connection](http://www.adobe.com/jp/devnet/phonegap/articles/phonegap-apps-powered-by-developercom.html)
* [PhoneGapチュートリアル](http://qiita.com/yudaifuijta0121/items/173068cc713568e92bb7)
* [GitHub(ChildBrowser版)](https://github.com/triceam/Database.Com-PhoneGap-Sample)
* [GitHub(InAppBrowser対応版)](https://github.com/nutti/Database.Com-PhoneGap-Sample)