【Cordova】WKWebView対応でハマった話 ①SQLite関連のエラー


2020年4月より、iOSアプリを新規申請する際にはWKWebView対応が必要となります。
(既存アプリの場合は、2020年12月以降の更新で対応が必要。)

Cordovaでアプリを作ると、デフォルトでUIWebViewを使用する(※執筆時)ため、
今後はこの対応が必要となってきます。

この記事では、自分がリリースしたアプリでWKWebView対応した際にハマったポイントを紹介していきます。


1.CordovaでのWKWebView対応

まずは今現在主流と思われる方法を、念のため記載します。

以下プラグインを使用します。
cordova-plugin-wkwebview-engine

インストール方法は上記リンク内に載っていますが、以下コマンドを実行します。
(Cordova iOSのバージョンは4.0以上である必要があるので、古い場合は最新等にします。)

cordova plugin add cordova-plugin-wkwebview-engine

プラグインを追加したら、config.xmlに以下を追記します。

<platform name="ios">
	<preference name="WKWebViewOnly" value="true" />
	
    <feature name="CDVWKWebViewEngine">
        <param name="ios-package" value="CDVWKWebViewEngine" />
    </feature>
    <preference name="CordovaWebViewEngine" value="CDVWKWebViewEngine" />
</platform>

これで対応自体は完了です。
問題はこの後で、UIWebViewとWKWebViewの仕様のズレによって、既存のアプリの動作に影響がでることがあります。

実際自分のアプリで上記を行った所、いくつか問題が発生したので、
発生した現象と対応方法をこの後紹介していきます。

2.SQLiteでエラー

見出しの通り、まず大きな問題としてSQLite関連のエラーが発生しました。
結果から見ると、そもそもの私の実装方法がマズかった可能性がありますが、一応紹介します。

症状

アプリ起動時のSQLiteデータベースへの接続でエラー。
当然、それ以降のDB関連の処理もすべてエラー

私のアプリは主にローカルDBにデータを保存していたので、これは非常に大きな問題でした。
調べてもピンポイントで何かがヒットするわけではなかったので、
地道にいろいろ試した結果、以下の2点を対処すると上手く動きました。

対処方法

① devicereadyイベントでDB接続を行う
② cordovaのSQLiteプラグイン(cordova-sqlite-storage)を使う

以下、それぞれの詳細を説明します。

対処① devicereadyイベント

対象のアプリにおけるデータベース接続処理は以下の様になっていました。
(実際のコードではなくイメージです。Vue.jsを使用しています。)

<script>
export default {
  name: 'App',
  data: function () {
    return {
      db: null
    }
  },
  created () {
    // デバイス判定
    window.setTimeout(() => {
      if (typeof cordova === 'undefined') {
        console.log('PC')
        this.onDeviceReady();
      } else {
        console.log('スマートフォン')
        document.addEventListener('deviceready', this.onDeviceReady, false)
      }
    }, 1000)

    // DB初期化
    this.db = window.openDatabase('test.db', '1.0', 'TEST DB', 100000)
    this.db.transaction(this.initDB, this.errorCB, this.successCB)
  },
  methods: {
    onDeviceReady () {
      console.log('device ready')
    },
    initDB: function (tx) {
      tx.executeSql(
        'CREATE TABLE IF NOT EXISTS sample (id integer PRIMARY KEY AUTOINCREMENT, name text)'
      )
    },
    errorCB: function (tx, err) {
      console.log('initDB Error : ' + err)
    },
    successCB: function () {
      console.log('initDB success!')
    }
}
</script>

かなり簡略化しましたが、構成的には上記のような感じです。
当初openDatabaseをどのタイミングで実行すべきかわからなかったので、
とりあえずcreatedで実装して問題が無かったのでそのままにしていました。(22行目)

さて、UIWebViewの時には上記の実装で問題が無かったのですが、WKWebView対応をしたタイミングでエラーを吐いたので、devicereadyイベント時にデータベース接続をするようにしました。
それが以下です。

<script>
export default {
  name: 'App',
  data: function () {
    return {
      db: null
    }
  },
  created () {
    console.log('--- [START]App created ---')
    // デバイス判定
    window.setTimeout(() => {
      if (typeof cordova === 'undefined') {
        console.log('on PC')
        this.onDeviceReady();
      } else {
        console.log('on スマートフォン')
        document.addEventListener('deviceready', this.onDeviceReady, false)
      }
    }, 1000)
  },
  methods: {
    onDeviceReady () {
      console.log('device ready')

      // DB初期化
      this.db = window.openDatabase('test.db', '1.0', 'TEST DB', 100000)
      this.db.transaction(this.initDB, this.errorCB, this.successCB)
    }
  } 
}

initDB等のメソッドは変わりないので割愛しています。
変わったのは、createdの中でDB初期化の処理をしていたのを、
onDeviceReadyメソッドの中で実行するように変更しました。
まず1点目はこちらになります。

対処② cordova-sqlite-storageを使う

もう一つ対応が必要だったのが、SQLite用のプラグインを使うことでした。
UIWebViewの時にも上記プラグインの存在は知っていたのですが、使わなくても動作したので使っていませんでした。
WKWebView対応でエラーを吐いたのをきっかけに、使って見たら上手く行ったという経緯です。

具体的な手順ですが、まずは以下でプラグインを追加します。

cordova plugin add cordova-sqlite-storage

そして、openDatabaseする際にこのプラグインを使うように変更します。
対象箇所はonDeviceReadyメソッド内で、以下の様に変更しました。

   onDeviceReady () {
      console.log('device ready')

      // DB初期化
      this.db = window.sqlitePlugin
        ? window.sqlitePlugin.openDatabase({name: 'test.db', location: 'default'})
        : window.openDatabase('test.db', '1.0', 'TEST DB', 100000)
      this.db.transaction(this.initDB, this.errorCB, this.successCB)
    }

2点目としてこちらを変更することで、WKWebViewに変更後もDB接続ができるようになりました。
どちらか片方だけで試したときはダメそうでしたので、どうやらこの2点両方が必要そうという結論でまとめています。
(原因を詳しく調査したわけではないので、帰納的な結論です。)

※余談ですが、ESLintによって文末のセミコロン禁止ルール(no-extra-semi)がかかっているので、
やや見辛いかもしれません。スミマセン。。


結果から見ると今回のケースは私の元々の実装方法がマズかった可能性が高いのですが、
備忘録として残しておきます。
この他にもWkWebView対応でハマった点がいくつかありますので、
次回以降の記事で紹介したいと思います。

  • このエントリーをはてなブックマークに追加

PAGE TOP