Table of Contents
Cocos2dx(js) で作成したアプリを Unity で作り直してアップデートした際、アプリ領域に保存したデータの移行を行ったので手順について記載します。
移行させるデータについて
Android における SharedPreferences と同様に、Cocos2dx では cc.sys.localStorage によってテキストや数値といったデータを保存できます。
// 例:キーと値のペアで数値データを保存する cc.sys.localStorage.setItem("number", 123); cc.log(cc.sys.localStorage.getItem("number"));
Cocos2dx でこのように保存したデータは SQLite3 によるデータベースとしてアプリ領域に保存されます。保存されるデータベースのファイル名は jsb.sqlite です。OSごとの保存パスは以下のようになっています。
Android では通常 data/data/[パッケージ名]/databases/jsb.sqlite iOS では /var/mobile/Containers/Data/Application/[アプリ固有ID]/Documents/jsb.sqlite
従って、Cocos2dx の保存データを Unity で読み込むためには、SQLite のテーブルから情報を取り出す処理が必要になります。
UnityでSQLiteを使うには
SQLite を扱う基本的なコードは以下からダウンロードできます。
このフレームワークに含まれる2つのソースコード(DataTable.cs、SqliteDatabase.cs)とSQLiteの実行ファイル libsqlite3.so を使用します。libsqlite3.so が含まれていますが、最新版をダウンロードしたい場合は”SQLite Download Page“から取得できます。
もしファイルが適切なディレクトリにあるにも関わらず、以下のようなエラー(DllNotFoundException)が出た場合はダウンロードし直してみると良いかも知れません。
ダウンロードした libsqlite3.so を、使いたい Unity のプロジェクトの Plugins ディレクトリに保存します。OSごとに保存するディレクトリが以下のように異なります。
Androidの場合
実行環境別にコピーして保存します。
Assets/Plugins/Android/libs/x86/libsqlite3.so Assets/Plugins/Android/libs/armeabi-v7a/libsqlite3.so Assets/Plugins/Android/libs/arm64-v8a/libsqlite3.so
Unity のインスペクターで、各実行環境に向けて設定(Platform Setting > CPU)を変更しておきます。
iOSの場合
以下のディレクトリに保存します。
Assets/Plugins/iOS/libsqlite3.so
SQLiteのデータベースを読み込むコード
libsqlite3.so の準備が終わったら、実際にデータを読み込むためのコードを用意します。
SqliteDatabase.cs を開き、コンストラクタから不要な機能を除去します。
/// <summary> /// Initializes a new instance of the <see cref="SqliteDatabase"/> class. /// </summary> /// <param name='dbName'> /// Data Base name. (the file needs exist in the streamingAssets folder) /// </param> public SqliteDatabase (string pathDB) { // 不要な機能を覗いたコンストラクタ this.pathDB = pathDB; }
また、マルチバイト文字を扱う予定があるのであれば、メソッド Prepare の書き換えを行います。
private IntPtr Prepare(string query) { IntPtr stmHandle; // クエリのバイト数を取得するように変更 int byteCount = System.Text.Encoding.UTF8.GetByteCount(query); if (sqlite3_prepare_v2(_connection, query, byteCount, out stmHandle, IntPtr.Zero) != SQLITE_OK) { IntPtr errorMsg = sqlite3_errmsg(_connection); throw new SqliteException(Marshal.PtrToStringAnsi(errorMsg)); } return stmHandle; }
以上の修正を終えたら、これを用いて SQLite からデータを読み取る処理を行うスクリプトを作成します。
例えば、以下のような関数を作成し、アプリ起動時に実行するようにします。
void ConvertOldData() { // 初回起動に一度だけ行うようにする if (PlayerPrefs.GetString("Convert") == "DONE") { print("読み込み済み"); return; } string dbFilename = "jsb.sqlite"; // 見つかったSQLiteデータベースのパスを格納する変数 string cocosDataPath = ""; #if UNITY_ANDROID string packageName = "your.app.package.name"; // 念の為、データベース保存の候補となりそうなディレクトリを検索 string[] possibleDataPaths = { "data/data/" + packageName + "/databases/" + dbFilename, "data/user/0/" + packageName + "/databases/" + dbFilename, "/mnt/sdcard/Android/data/" + packageName + "/databases/" + dbFilename, "/storage/emulated/0/Android/data/" + packageName + "/databases/" + dbFilename, }; foreach (string path in possibleDataPaths) { if (File.Exists(path)) { print("FILE FOUND AT: " + path); cocosDataPath = path; break; } print("SEARCHED: " + path); } if (cocosDataPath == "") { print("NO FILE FOUND"); return; } #elif UNITY_IOS cocosDataPath = Application.persistentDataPath + "/" + dbFilename; if (!File.Exists(cocosDataPath)) { print("NO FILE FOUND AT: " + cocosDataPath); return; } #endif // Cocos2dx で作成されるデータテーブル名は data なので string tableName = "data"; SqliteDatabase sqlDB = new SqliteDatabase(cocosDataPath); // データ取得 string selectQuery = "select * from " + tableName; SqliteDataTable dataTable = sqlDB.ExecuteQuery(selectQuery); // データベースにある全てのキーと値のペアを取得 foreach (DataRow row in dataTable.Rows) { string key = (string)row["key"]; string val = (string)row["value"]; print(key + ": " + val); } }
iOS では、保存パスは Application.persistentDataPath を使って簡単に取得できます。
Application.persistentDataPath + "/jsb.sqlite";
Android では、機種によって保存領域が異なる可能性があるため、念の為複数のディレクトリを確認していますが、通常は data/data/[パッケージ名]/databases/ 以下に保存されるはずです。
以上のコードによって、保存されたキーと値のペアが取得できますので、それをそのまま利用したり PlayerPrefs に保存し直したりすることができます。
Cocos2dxのデータを読み込む際の注意点
cc.sys.localStorage で保存したデータは Unity で読み込んだ場合、全て文字列として扱われます。
よって、PlayerPrefs に保存し直したりする場合、元々数値やブール値で保存したものはパースによって数値(intやfloat)やブール値(true/false)に変換する必要があります。
// 数値の取得とパース int result; if (int.TryParse(val, out result)) { PlayerPrefs.SetInt(key, result); } float resultF; if (float.TryParse(val, out resultF)) { PlayerPrefs.SetFloat(key, resultF); } // bool の取得とパース bool getBool; if (key == "flag") { getBool = (val == "true"); }
以上、Cocos2dx製アプリの保存データをUnity製アプリに移行する方法についてでした。