Cordova NativeStorageプラグインでデータを保存

NativeStorageプラグインを使用するとアプリのデータを永続的に保存できます。Androidの場合はSharedPreferences、iOSの場合はNSUserDefaultsを利用します。データはローカルストレージ(LocalStorage)と同様にKey-Value形式で扱います。

NativeStorageプラグイン: cordova-plugin-nativestorage

API

const key = "message";
const value = "hello";
const successCallback => console.log("success");
const errorCallback => console.log("error");

// 保存
NativeStorage.setItem(key, value, successCallback, errorCallback);

// 読み出し
NativeStorage.getItem(key, successCallback, errorCallback);

// 読み出し(全キー)
NativeStorage.keys(successCallback, errorCallback);

// 削除
NativeStorage.remove(key, successCallback, errorCallback);

// 全削除
NativeStorage.clear(successCallback, errorCallback);

動作確認サンプル

<body>
  <div id="container">
    <ons-button onclick="onLoad()">Load</ons-button>
    <ons-button onclick="onSave()">Save</ons-button>
  </div>
</body>
// key
const KEY_NUMBERS = "nsNums";
const KEY_RECORDS = "nsRecords";

// value
const numbers = [100, 200, 300, 400, 500];  // 配列
const records = {     // オブジェクト
  "date": {
    "year": 2019,
    "month": 11,
    "day": 16,
    "week": 1
  },
  "time": [
    {"hour": 7, "min": 10},
    {"hour": 9, "min": 20},
    {"hour": 11, "min": 30},
    {"hour": 15, "min": 40},
    {"hour": 20, "min": 50}
  ]
};

ons.ready(function () {   // devicereadyイベント
  console.log("*** ons.ready ***");
  console.log(window.NativeStorage);
})

function onLoad () {
  console.log("*** onLoad ***");

  NativeStorage.getItem(KEY_NUMBERS, 
    obj => console.log("success", obj),
    err => console.log("error", err.code));

  console.log("check1");

  NativeStorage.getItem(KEY_RECORDS, 
    obj => console.log("success", obj),
    err => console.log("error", err.code));

  console.log("check2");
}

function onSave () {
  console.log("*** onSave ***");
  
  NativeStorage.setItem(KEY_NUMBERS, numbers,
    obj => console.log("success", obj),
    err => console.log("error", err.code));

  console.log("check1");

  NativeStorage.setItem(KEY_RECORDS, records, 
    obj => console.log("success", obj),
    err => console.log("error", err.code));

  console.log("check2");
}

console 出力

ローカルストレージとの相違点

アプリ起動時の読み込み

  • Cordovaの初期化が終わってから(devicereadyイベントリスナ―やons.ready()メソッドで)実行する
  • ローカルストレージの場合はどこで読み込んでもよい

非同期処理

  • データを読み出した後の処理はコールバックで行う
  • 複数のキーを順に呼び出したりFile APIのような非同期処理を続けて行うときはPromiseなどを使用するとソースコードが見やすくなる
  • ローカルストレージの場合は同期処理なので記述した順番に実行される

データ形式

  • オブジェクトや配列のデータを保存したり読み出したりする場合、そのままの形式で扱うことができる
  • ローカルストレージの場合はJSON形式の文字列で扱う必要がある(保存する前にJSON.stringify()で文字列に、読み出した後はJSON.parse()でオブジェクトに変換)

Note

SharedPreferencesへのアクセスモードはMODE_PRIVATE固定

NativeStorageプラグインでは他のアプリとのデータ共有は不可。そもそもSharedPreferences APIではAPI level23からMODE_MULTI_PROCESSがサポートされなくなったため、データ共有したい場合はSharedPreferencesの替わりにContentProviderなどを使用する必要がある。

アプリを再インストールしてもデータが消えない

アプリをアンインストールした後に再インストールした場合、SharedPreferencesに保存したデータは自動的に復元される。保存したデータが設定値であれば再設定する手間が省けるなど便利な面もあるが、スコアや過去の日付のような初期化したいデータの場合はクリーンな状態から始めることができなくなる。

これは、Androidの自動バックアップ機能が原因。

この機能により、SharedPreferencesがGoogle Driveへ自動的に保存され、再インストールしたときに自動的に復元される。この機能を無効化するには、アプリのマニフェストファイルにandroid:allowBackup=”false”を記述する。Monacaを使用している場合はAndroidManifest.xmlの替わりにconfig.xmlとCustom Configプラグインを使用する。

Cordova AdMob Freeプラグインで広告を表示

はじめに

最近知ったのですが、以前記事にしたCordova AdMobプラグインcordova-admob-proにはちょっとした問題があるようです。プラグイン作成者は無料で利用する場合は2%のユーザートラフィックを共有させてもらうだけで大丈夫ですと公表しているのですが、ユーザーが調べたところ30%共有されていたケースがあったそうです。(ユーザーに入る広告費が30%減るということみたいです)

cordova-plugin-admobpro issues #354

そこでRatsonさんが完全無料のAdMobプラグインcordova-plugin-admob-freeを開発しました(開発へ至るまでの経緯はこちら)。

Ratsonさんはcordova-plugin-admob-freeプラグインの後継となるadmob-plusプラグインも開発中です。

環境

参考にした情報

実装手順

MonacaのOnsen UI + VueプロジェクトでAdMob Freeプラグインを利用します。本内容はteratailで解説されていますので詳細についてはそちらをご参照ください。

1.AdMob SDKプラグインをダウンロード

https://gitlab.com/ratson/cordova-admob-sdk からzipファイルをダウンロードします。

2.AdMob SDKプラグインをインポート

Cordovaプラグインの設定画面からさきほどダウンロードしたzipファイル(cordova-admob-sdk-master.zip)を選択してAdMob SDKプラグインをインポートします。

3.AdMob Freeプラグインをインポート

Cordovaプラグインの設定画面からパッケージ名を入力してAdMob Freeプラグインをインポートします。

パッケージ名/URL :cordova-plugin-admob-free@0.27.0

4. ADMOB_APP_ID の設定

AdMob FreeプラグインのインストールパラメータにAdMobのアプリIDを設定します。

インストールパラメータ :ADMOB_APP_ID=ca-app-pub-1234567890…

以上でプラグインの設定は完了です。

5.サンプルコード

AdMob Freeプラグインのexamplesを参考にしています。

App.Vue
<template>
    <v-ons-page>
      <v-ons-toolbar>
        <div class="center">{{ title }}</div>
        <div class="right">
          <v-ons-toolbar-button>
            <v-ons-icon icon="ion-navicon, material: md-menu"></v-ons-icon>
          </v-ons-toolbar-button>
        </div>
      </v-ons-toolbar>
      <div style="text-align: center; padding-top:10px">Hello World!</div>
      <p style="text-align: center">
        <v-ons-button @click="banner">Banner</v-ons-button>
        <v-ons-button @click="interstitial">Interstitial</v-ons-button>
      </p>
    </v-ons-page>
</template>
<script>
  export default{
    data() {
      return {
        title: 'My app'
      };
    },
    beforeCreate () {
      this.$ons.ready(function() {
        var admobid = {
          banner: 'ca-app-pub-3940256099942544/6300978111',
          interstitial: 'ca-app-pub-3940256099942544/1033173712'
        }
        // Banner
        admob.banner.config({
          id: admobid.banner,
          isTesting: true,
          autoShow: false,
        })
        admob.banner.prepare()
          .then (() => {
            console.log('banner prepare success!')
          })
          .catch (err => {
            console.log('banner prepare error!', err)
          })

        // Interstitial
        admob.interstitial.config({
          id: admobid.interstitial,
          isTesting: true,
          autoShow: false,
        })
        admob.interstitial.prepare()
          .then (() => {
            console.log('interstitial prepare success!')
          })
          .catch (err => {
            console.log('interstitial prepare error!', err)
          })

      })  // ons.ready

      document.addEventListener('admob.banner.events.LOAD_FAIL', function(event) {
        console.log("LOAD_FAIL banner", event)
      })

      document.addEventListener('admob.interstitial.events.LOAD_FAIL', function(event) {
        console.log("LOAD_FAIL interstitial", event)
      })

      document.addEventListener('admob.interstitial.events.LOAD', function(event) {
        console.log("LOAD", event)
      })

      document.addEventListener('admob.interstitial.events.CLOSE', function(event) {
        console.log("CLOSE", event)

        admob.interstitial.prepare()
      })
    },
    methods: {
      banner () {
        admob.banner.show()
      },
      interstitial () {
        admob.interstitial.show()
      }
    }
  }
</script>

6.AdMob広告の表示確認

プロジェクトをデバッグビルドしAndroid端末にインストールして確認しました。

バナー広告

インタースティシャル広告

テスト広告について

Google AdMobのガイドには次のように記載されています。

アプリの開発やテストでは実際の広告を使用せず、必ずテスト広告を使ってください。実際の広告でテストすると、アカウントが停止される場合があります。

https://developers.google.com/admob/android/banner?hl=ja

GoogleはAdMobアカウントと関連付けられていないテスト用の広告ユニットを提供しています。以下のリンク先に記載しているサンプル広告ユニットIDを自由に利用することができます。

テスト広告 – Google AdMob > Mobile Ads SDK(Android)

広告フォーマットサンプル広告ユニット ID
バナーca-app-pub-3940256099942544/6300978111
インタースティシャルca-app-pub-3940256099942544/1033173712
インタースティシャル動画ca-app-pub-3940256099942544/8691691433
動画リワードca-app-pub-3940256099942544/5224354917
ネイティブ アドバンスca-app-pub-3940256099942544/2247696110
ネイティブ アドバンス動画ca-app-pub-3940256099942544/1044960115

特記事項(2019/9/8追記)

当時の私のケースになりますが、アプリのリリース直前にisTestingfalseにして最終確認を行ったところ、広告が表示されませんでした。原因が分からず不安だったのですが、いったんGoogle Play Consoleでベータ版としてリリースし動作確認したところ、広告が表示されました。製品版としてリリースしたアプリでも表示されました。本番用の広告を表示するためにはGoogle Playストアを介す必要があるのかもしれません。ご参考まで。

Cordova AdMobプラグインで広告を表示

AdMobプラグインを使用するとGoogle AdMobの提供する広告配信サービスを利用してモバイルアプリに広告を表示することができます。

floatinghotpot/cordova-admob-pro

バナー広告

AdMob.createBanner({
  adId: 'ca-app-pub-0123456789012345/0123456789',
  position: AdMob.AD_POSITION.BOTTOM_CENTER,
//debug
//  isTesting: true,
  overlap: true,
  autoShow: true,
  adSize: 'SMART_BANNER'
});

バナー広告(AD_POSITION.POS_XY)

var elt = document.getElementById("med_page");
var rect = elt.getBoundingClientRect();
var y = (rect.bottom - rect.top) + window.pageYOffset;  // タブバーを含まない画面の高さ

y *= parseFloat(document.body.style.zoom);  // 元の画面サイズ(CSSピクセル、dp単位)に戻す
if (window.screen.height > 720) {  // スマートバナーの高さを引く
  y -= 90;
} else if (window.screen.height > 400){
  y -= 50;
} else {
  y -= 32;
}
y *= window.devicePixelRatio;  // CSSピクセル(dp)からデバイスピクセルに変換する

AdMob.createBanner({
  adId: 'ca-app-pub-0123456789012345/0123456789',
  position: AdMob.AD_POSITION.POS_XY,
  x: 0,
  y: y,
//debug
//  isTesting: true,
  overlap: true,
  autoShow: true,
  adSize: 'SMART_BANNER'
});

インタースティシャル広告

var elem = document.getElementById("myNavigator");
elem.addEventListener("postpop", function(e) {
  if (e.leavePage.id === "graph_page") {  // グラフ画面からポップした後
    showInterstitialPolling(10);
  }
});
elem.addEventListener("postpush", function(e) {
  if (e.enterPage.id === "graph_page") {  // グラフ画面へプッシュした後
    if (window.AdMob) {
      init_ad();
    }
  }
});

function showInterstitialPolling(count) {
  if (--count < 0) return;
  if (window.AdMob) {
    AdMob.isInterstitialReady(function(isready) {
      if (isready) {
        AdMob.showInterstitial();
      } else {
        setTimeout(function() {showInterstitialPolling(count)}, 200);
      }
    });
  }
}
function init_ad() {
  if (window.AdMob) {
    AdMob.prepareInterstitial({
      adId: 'ca-app-pub-0123456789012345/0123456789',
//debug
//      isTesting: true,
      autoShow: false
    });
  }
}

Note

adIdプロパティにはアプリIDではなく広告ユニットIDを設定します(数字の区切りに「~」ではなく「/」を使用している方です)。