diff --git a/Android/MMKV/gradle.properties b/Android/MMKV/gradle.properties index e6a93ba9..50b7c023 100644 --- a/Android/MMKV/gradle.properties +++ b/Android/MMKV/gradle.properties @@ -14,7 +14,7 @@ org.gradle.jvmargs=-Xmx1536m # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true -VERSION_NAME_PREFIX=1.2.15 +VERSION_NAME_PREFIX=1.2.16 #VERSION_NAME_SUFFIX=-SNAPSHOT VERSION_NAME_SUFFIX= diff --git a/Android/MMKV/mmkv/src/main/java/com/tencent/mmkv/MMKVContentProvider.java b/Android/MMKV/mmkv/src/main/java/com/tencent/mmkv/MMKVContentProvider.java index 77b40d68..2efba850 100644 --- a/Android/MMKV/mmkv/src/main/java/com/tencent/mmkv/MMKVContentProvider.java +++ b/Android/MMKV/mmkv/src/main/java/com/tencent/mmkv/MMKVContentProvider.java @@ -94,14 +94,6 @@ public boolean onCreate() { if (context == null) { return false; } - String authority = queryAuthority(context); - if (authority == null) { - return false; - } - - if (MMKVContentProvider.gUri == null) { - MMKVContentProvider.gUri = Uri.parse(ContentResolver.SCHEME_CONTENT + "://" + authority); - } return true; } diff --git a/Android/MMKV/mmkvdemo/build.gradle b/Android/MMKV/mmkvdemo/build.gradle index 7189b441..e50030d2 100644 --- a/Android/MMKV/mmkvdemo/build.gradle +++ b/Android/MMKV/mmkvdemo/build.gradle @@ -76,9 +76,9 @@ repositories { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation project(':mmkv') -// implementation 'com.tencent:mmkv:1.2.15' -// implementation 'com.tencent:mmkv-static:1.2.15' // this is identical to 'com.tencent:mmkv' -// implementation 'com.tencent:mmkv-shared:1.2.15' +// implementation 'com.tencent:mmkv:1.2.16' +// implementation 'com.tencent:mmkv-static:1.2.16' // this is identical to 'com.tencent:mmkv' +// implementation 'com.tencent:mmkv-shared:1.2.16' implementation 'androidx.appcompat:appcompat:1.6.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' testImplementation 'junit:junit:4.13.2' diff --git a/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/Baseline.java b/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/Baseline.java index 01b40621..974ec172 100644 --- a/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/Baseline.java +++ b/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/Baseline.java @@ -148,8 +148,8 @@ private void mmkvBatchDeleteString() { public void sharedPreferencesBaselineTest() { spBatchWriteInt(); spBatchReadInt(); - spBatchWrieString(); - spBatchReadStrinfg(); + spBatchWriteString(); + spBatchReadString(); } private void spBatchWriteInt() { @@ -181,7 +181,7 @@ private void spBatchReadInt() { Log.i(TAG, "SharedPreferences read int: loop[" + m_loops + "]: " + m_formatter.format(endTime) + " ms"); } - private void spBatchWrieString() { + private void spBatchWriteString() { long startTime = System.nanoTime(); SharedPreferences preferences = m_context.getSharedPreferences(MMKV_ID, MODE_PRIVATE); @@ -197,7 +197,7 @@ private void spBatchWrieString() { Log.i(TAG, "SharedPreferences write String: loop[" + m_loops + "]: " + m_formatter.format(endTime) + " ms"); } - private void spBatchReadStrinfg() { + private void spBatchReadString() { long startTime = System.nanoTime(); SharedPreferences preferences = m_context.getSharedPreferences(MMKV_ID, MODE_PRIVATE); @@ -220,17 +220,17 @@ private void sqliteWriteInt(boolean useTransaction) { Random r = new Random(); long startTime = System.nanoTime(); - SQLIteKV sqlIteKV = new SQLIteKV(m_context); + SQLiteKV sqliteKV = new SQLiteKV(m_context); if (useTransaction) { - sqlIteKV.beginTransaction(); + sqliteKV.beginTransaction(); } for (int index = 0; index < m_loops; index++) { int tmp = r.nextInt(); String key = m_arrIntKeys[index]; - sqlIteKV.putInt(key, tmp); + sqliteKV.putInt(key, tmp); } if (useTransaction) { - sqlIteKV.endTransaction(); + sqliteKV.endTransaction(); } double endTime = (System.nanoTime() - startTime) / 1000000.0; final String msg = useTransaction ? "sqlite transaction" : "sqlite"; @@ -240,16 +240,16 @@ private void sqliteWriteInt(boolean useTransaction) { private void sqliteReadInt(boolean useTransaction) { long startTime = System.nanoTime(); - SQLIteKV sqlIteKV = new SQLIteKV(m_context); + SQLiteKV sqliteKV = new SQLiteKV(m_context); if (useTransaction) { - sqlIteKV.beginTransaction(); + sqliteKV.beginTransaction(); } for (int index = 0; index < m_loops; index++) { String key = m_arrIntKeys[index]; - int tmp = sqlIteKV.getInt(key); + int tmp = sqliteKV.getInt(key); } if (useTransaction) { - sqlIteKV.endTransaction(); + sqliteKV.endTransaction(); } double endTime = (System.nanoTime() - startTime) / 1000000.0; final String msg = useTransaction ? "sqlite transaction" : "sqlite"; @@ -259,17 +259,17 @@ private void sqliteReadInt(boolean useTransaction) { private void sqliteWriteString(boolean useTransaction) { long startTime = System.nanoTime(); - SQLIteKV sqlIteKV = new SQLIteKV(m_context); + SQLiteKV sqliteKV = new SQLiteKV(m_context); if (useTransaction) { - sqlIteKV.beginTransaction(); + sqliteKV.beginTransaction(); } for (int index = 0; index < m_loops; index++) { final String value = m_arrStrings[index]; final String key = m_arrKeys[index]; - sqlIteKV.putString(key, value); + sqliteKV.putString(key, value); } if (useTransaction) { - sqlIteKV.endTransaction(); + sqliteKV.endTransaction(); } double endTime = (System.nanoTime() - startTime) / 1000000.0; final String msg = useTransaction ? "sqlite transaction" : "sqlite"; @@ -279,16 +279,16 @@ private void sqliteWriteString(boolean useTransaction) { private void sqliteReadString(boolean useTransaction) { long startTime = System.nanoTime(); - SQLIteKV sqlIteKV = new SQLIteKV(m_context); + SQLiteKV sqliteKV = new SQLiteKV(m_context); if (useTransaction) { - sqlIteKV.beginTransaction(); + sqliteKV.beginTransaction(); } for (int index = 0; index < m_loops; index++) { final String key = m_arrKeys[index]; - final String tmp = sqlIteKV.getString(key); + final String tmp = sqliteKV.getString(key); } if (useTransaction) { - sqlIteKV.endTransaction(); + sqliteKV.endTransaction(); } double endTime = (System.nanoTime() - startTime) / 1000000.0; final String msg = useTransaction ? "sqlite transaction" : "sqlite"; diff --git a/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/BenchMarkBaseService.java b/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/BenchMarkBaseService.java index d93541d0..bfea03ae 100644 --- a/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/BenchMarkBaseService.java +++ b/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/BenchMarkBaseService.java @@ -27,7 +27,6 @@ import android.util.Log; import androidx.annotation.Nullable; import com.tencent.mmkv.MMKV; -import com.tencent.mmkv.MMKVLogLevel; import com.tencent.mmkv.ParcelableMMKV; import java.util.Random; @@ -121,17 +120,17 @@ private void sqliteWriteInt(String caller, boolean useTransaction) { Random r = new Random(); long startTime = System.currentTimeMillis(); - SQLIteKV sqlIteKV = new SQLIteKV(this); + SQLiteKV sqliteKV = new SQLiteKV(this); if (useTransaction) { - sqlIteKV.beginTransaction(); + sqliteKV.beginTransaction(); } for (int index = 0; index < m_loops; index++) { int tmp = r.nextInt(); String key = m_arrIntKeys[index]; - sqlIteKV.putInt(key, tmp); + sqliteKV.putInt(key, tmp); } if (useTransaction) { - sqlIteKV.endTransaction(); + sqliteKV.endTransaction(); } long endTime = System.currentTimeMillis(); final String msg = useTransaction ? " sqlite transaction " : " sqlite "; @@ -178,16 +177,16 @@ private void mmkvBatchReadInt(String caller) { private void sqliteReadInt(String caller, boolean useTransaction) { long startTime = System.currentTimeMillis(); - SQLIteKV sqlIteKV = new SQLIteKV(this); + SQLiteKV sqliteKV = new SQLiteKV(this); if (useTransaction) { - sqlIteKV.beginTransaction(); + sqliteKV.beginTransaction(); } for (int index = 0; index < m_loops; index++) { String key = m_arrIntKeys[index]; - int tmp = sqlIteKV.getInt(key); + int tmp = sqliteKV.getInt(key); } if (useTransaction) { - sqlIteKV.endTransaction(); + sqliteKV.endTransaction(); } long endTime = System.currentTimeMillis(); final String msg = useTransaction ? " sqlite transaction " : " sqlite "; @@ -230,17 +229,17 @@ private void mmkvBatchWriteString(String caller) { private void sqliteWriteString(String caller, boolean useTransaction) { long startTime = System.currentTimeMillis(); - SQLIteKV sqlIteKV = new SQLIteKV(this); + SQLiteKV sqliteKV = new SQLiteKV(this); if (useTransaction) { - sqlIteKV.beginTransaction(); + sqliteKV.beginTransaction(); } for (int index = 0; index < m_loops; index++) { final String value = m_arrStrings[index]; final String key = m_arrKeys[index]; - sqlIteKV.putString(key, value); + sqliteKV.putString(key, value); } if (useTransaction) { - sqlIteKV.endTransaction(); + sqliteKV.endTransaction(); } long endTime = System.currentTimeMillis(); final String msg = useTransaction ? " sqlite transaction " : " sqlite "; @@ -286,16 +285,16 @@ private void mmkvBatchReadString(String caller) { private void sqliteReadString(String caller, boolean useTransaction) { long startTime = System.currentTimeMillis(); - SQLIteKV sqlIteKV = new SQLIteKV(this); + SQLiteKV sqliteKV = new SQLiteKV(this); if (useTransaction) { - sqlIteKV.beginTransaction(); + sqliteKV.beginTransaction(); } for (int index = 0; index < m_loops; index++) { final String key = m_arrKeys[index]; - final String tmp = sqlIteKV.getString(key); + final String tmp = sqliteKV.getString(key); } if (useTransaction) { - sqlIteKV.endTransaction(); + sqliteKV.endTransaction(); } long endTime = System.currentTimeMillis(); final String msg = useTransaction ? " sqlite transaction " : " sqlite "; diff --git a/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/SQLIteKV.java b/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/SQLiteKV.java similarity index 89% rename from Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/SQLIteKV.java rename to Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/SQLiteKV.java index c7fad436..70ed0ce6 100644 --- a/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/SQLIteKV.java +++ b/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/SQLiteKV.java @@ -26,14 +26,14 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; -public final class SQLIteKV { - private static class SQLIteKVDBHelper extends SQLiteOpenHelper { +public final class SQLiteKV { + private static class SQLiteKVDBHelper extends SQLiteOpenHelper { private static final int DB_VERSION = 1; private static final String DB_NAME = "kv.db"; public static final String TABLE_NAME_STR = "kv_str"; public static final String TABLE_NAME_INT = "kv_int"; - public SQLIteKVDBHelper(Context context) { + public SQLiteKVDBHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); } @@ -55,12 +55,12 @@ public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVers onCreate(sqLiteDatabase); } } - private SQLIteKVDBHelper m_dbHelper; + private SQLiteKVDBHelper m_dbHelper; private SQLiteDatabase m_writetableDB; private SQLiteDatabase m_readableDB; - public SQLIteKV(Context context) { - m_dbHelper = new SQLIteKVDBHelper(context); + public SQLiteKV(Context context) { + m_dbHelper = new SQLiteKVDBHelper(context); m_dbHelper.setWriteAheadLoggingEnabled(true); } @@ -107,14 +107,14 @@ public boolean putInt(String key, int value) { ContentValues contentValues = new ContentValues(); contentValues.put("k", key); contentValues.put("v", value); - long rowID = getWritetableDB().insert(SQLIteKVDBHelper.TABLE_NAME_INT, null, contentValues); + long rowID = getWritetableDB().insert(SQLiteKVDBHelper.TABLE_NAME_INT, null, contentValues); return rowID != -1; } public int getInt(String key) { int value = 0; Cursor cursor = getReadableDatabase().rawQuery( - "select v from " + SQLIteKVDBHelper.TABLE_NAME_INT + " where k=?", new String[] {key}); + "select v from " + SQLiteKVDBHelper.TABLE_NAME_INT + " where k=?", new String[] {key}); if (cursor.moveToFirst()) { value = cursor.getInt(cursor.getColumnIndex("v")); } @@ -126,14 +126,14 @@ public boolean putString(String key, String value) { ContentValues contentValues = new ContentValues(); contentValues.put("k", key); contentValues.put("v", value); - long rowID = getWritetableDB().insert(SQLIteKVDBHelper.TABLE_NAME_STR, null, contentValues); + long rowID = getWritetableDB().insert(SQLiteKVDBHelper.TABLE_NAME_STR, null, contentValues); return rowID != -1; } public String getString(String key) { String value = null; Cursor cursor = getReadableDatabase().rawQuery( - "select v from " + SQLIteKVDBHelper.TABLE_NAME_STR + " where k=?", new String[] {key}); + "select v from " + SQLiteKVDBHelper.TABLE_NAME_STR + " where k=?", new String[] {key}); if (cursor.moveToFirst()) { value = cursor.getString(cursor.getColumnIndex("v")); } diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ca0348e..7fd57e41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # MMKV Change Log +## v1.2.16 / 2023-04-20 +### Changes for All platforms +* Optimization: The actual file content is lazy loaded now, saving time on MMKV instance creation, and avoiding lock waiting when a lot of instances are created at the same time. +* Fix a bug when restoring a loaded MMKV instance the meta file might mistakenly report corrupted. + +### Android +* Optimization: Remove unnecessary binder call on main process instantiation. + +### Flutter +* Fix a crash on decoding an empty list. +* Remove deprecated dependence. +* Make the script more robust to fix the iOS Flutter plugin name. + +### Win32 +* Fix a string format bug on the MinGW64 environment. + +### golang +* Fix a build error on 32-bit OS. + ## v1.2.15 / 2023-01-12 ### Changes for All platforms * Log handler now handles all logs from the very beginning, especially the logs in initialization. @@ -13,6 +32,7 @@ * Fix a compile error on macOS. * Fix a bug that some ObjC exceptions are not being caught. * Add assert on nil MMKV base path, protect from mis-using MMKV in global variable initialization. +* Starting from v1.2.15, one must call `+[MMKV initializeMMKV:]` manually before calling any MMKV methods. ### golang * Fix a compile error on GCC. diff --git a/Core/MMKV.cpp b/Core/MMKV.cpp index fb52af6b..0c3e0496 100755 --- a/Core/MMKV.cpp +++ b/Core/MMKV.cpp @@ -116,11 +116,6 @@ MMKV::MMKV(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *ro m_sharedProcessLock->m_enable = m_isInterProcess; m_exclusiveProcessLock->m_enable = m_isInterProcess; - // sensitive zone - { - SCOPED_LOCK(m_sharedProcessLock); - loadFromFile(); - } } #endif @@ -307,6 +302,7 @@ void MMKV::clearMemoryCache() { m_output = nullptr; m_file->clearMemoryCache(); + m_metaFile->clearMemoryCache(); m_actualSize = 0; m_metaInfo->m_crcDigest = 0; } @@ -999,7 +995,7 @@ static bool backupOneToDirectoryByFilePath(const string &mmapKey, const MMKVPath bool ret = false; { #ifdef MMKV_WIN32 - MMKVInfo("backup one mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str()); + MMKVInfo("backup one mmkv[%s] from [%ls] to [%ls]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str()); #else MMKVInfo("backup one mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str()); #endif @@ -1039,7 +1035,7 @@ bool MMKV::backupOneToDirectory(const string &mmapKey, const MMKVPath_t &dstPath // get one in cache, do it the easy way if (kv) { #ifdef MMKV_WIN32 - MMKVInfo("backup one cached mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str()); + MMKVInfo("backup one cached mmkv[%s] from [%ls] to [%ls]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str()); #else MMKVInfo("backup one cached mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str()); #endif @@ -1113,7 +1109,7 @@ size_t MMKV::backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t &sr auto srcCRCPath = srcPath + CRC_SUFFIX; if (mmapIDCRCSet.find(srcCRCPath) == mmapIDCRCSet.end()) { #ifdef MMKV_WIN32 - MMKVWarning("crc not exist [%ws]", srcCRCPath.c_str()); + MMKVWarning("crc not exist [%ls]", srcCRCPath.c_str()); #else MMKVWarning("crc not exist [%s]", srcCRCPath.c_str()); #endif @@ -1158,7 +1154,7 @@ static bool restoreOneFromDirectoryByFilePath(const string &mmapKey, const MMKVP bool ret = false; { #ifdef MMKV_WIN32 - MMKVInfo("restore one mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str()); + MMKVInfo("restore one mmkv[%s] from [%ls] to [%ls]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str()); #else MMKVInfo("restore one mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str()); #endif @@ -1200,7 +1196,7 @@ bool MMKV::restoreOneFromDirectory(const string &mmapKey, const MMKVPath_t &srcP // get one in cache, do it the easy way if (kv) { #ifdef MMKV_WIN32 - MMKVInfo("restore one cached mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str()); + MMKVInfo("restore one cached mmkv[%s] from [%ls] to [%ls]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str()); #else MMKVInfo("restore one cached mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str()); #endif @@ -1267,7 +1263,7 @@ size_t MMKV::restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t auto srcCRCPath = srcPath + CRC_SUFFIX; if (mmapIDCRCSet.find(srcCRCPath) == mmapIDCRCSet.end()) { #ifdef MMKV_WIN32 - MMKVWarning("crc not exist [%ws]", srcCRCPath.c_str()); + MMKVWarning("crc not exist [%ls]", srcCRCPath.c_str()); #else MMKVWarning("crc not exist [%s]", srcCRCPath.c_str()); #endif diff --git a/Core/MMKVPredef.h b/Core/MMKVPredef.h index 250a5b13..1fa1b683 100755 --- a/Core/MMKVPredef.h +++ b/Core/MMKVPredef.h @@ -34,7 +34,7 @@ #include #include -constexpr auto MMKV_VERSION = "v1.2.15"; +constexpr auto MMKV_VERSION = "v1.2.16"; #ifdef DEBUG # define MMKV_DEBUG @@ -84,7 +84,7 @@ constexpr auto MMKV_VERSION = "v1.2.15"; # include constexpr auto MMKV_PATH_SLASH = L"\\"; -# define MMKV_PATH_FORMAT "%ws" +# define MMKV_PATH_FORMAT "%ls" using MMKVFileHandle_t = HANDLE; using MMKVPath_t = std::wstring; extern MMKVPath_t string2MMKVPath_t(const std::string &str); diff --git a/Core/MMKV_Android.cpp b/Core/MMKV_Android.cpp index f4b498b5..a4351eae 100644 --- a/Core/MMKV_Android.cpp +++ b/Core/MMKV_Android.cpp @@ -79,11 +79,6 @@ MMKV::MMKV(const string &mmapID, int size, MMKVMode mode, string *cryptKey, stri m_sharedProcessLock->m_enable = m_isInterProcess; m_exclusiveProcessLock->m_enable = m_isInterProcess; - // sensitive zone - { - SCOPED_LOCK(m_sharedProcessLock); - loadFromFile(); - } } MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, string *cryptKey) @@ -128,11 +123,6 @@ MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, string *cryptKe m_sharedProcessLock->m_enable = m_isInterProcess; m_exclusiveProcessLock->m_enable = m_isInterProcess; - // sensitive zone - { - SCOPED_LOCK(m_sharedProcessLock); - loadFromFile(); - } } MMKV *MMKV::mmkvWithID(const string &mmapID, int size, MMKVMode mode, string *cryptKey, string *rootPath) { diff --git a/Core/MMKV_IO.cpp b/Core/MMKV_IO.cpp index c8ed2889..bb77bebd 100644 --- a/Core/MMKV_IO.cpp +++ b/Core/MMKV_IO.cpp @@ -57,7 +57,12 @@ constexpr uint32_t Fixed32Size = pbFixed32Size(); MMKV_NAMESPACE_BEGIN void MMKV::loadFromFile() { - if (m_metaFile->isFileValid()) { + if (!m_metaFile->isFileValid()) { + m_metaFile->reloadFromFile(); + } + if (!m_metaFile->isFileValid()) { + MMKVError("file [%s] not valid", m_metaFile->getPath().c_str()); + } else { m_metaInfo->read(m_metaFile->getMemory()); } #ifndef MMKV_DISABLE_CRYPT diff --git a/Core/MemoryFile_Win32.cpp b/Core/MemoryFile_Win32.cpp index a8646f75..8f67b37f 100755 --- a/Core/MemoryFile_Win32.cpp +++ b/Core/MemoryFile_Win32.cpp @@ -70,20 +70,20 @@ bool File::open() { m_fd = CreateFile(m_path.c_str(), pair.first, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, pair.second, FILE_ATTRIBUTE_NORMAL, nullptr); if (!isFileValid()) { - MMKVError("fail to open:[%ws], %d", m_path.c_str(), GetLastError()); + MMKVError("fail to open:[%ls], %d", m_path.c_str(), GetLastError()); return false; } - MMKVInfo("open fd[%p], %ws", m_fd, m_path.c_str()); + MMKVInfo("open fd[%p], %ls", m_fd, m_path.c_str()); return true; } void File::close() { if (isFileValid()) { - MMKVInfo("closing fd[%p], %ws", m_fd, m_path.c_str()); + MMKVInfo("closing fd[%p], %ls", m_fd, m_path.c_str()); if (CloseHandle(m_fd)) { m_fd = INVALID_HANDLE_VALUE; } else { - MMKVError("fail to close [%ws], %d", m_path.c_str(), GetLastError()); + MMKVError("fail to close [%ls], %d", m_path.c_str(), GetLastError()); } } } @@ -118,13 +118,13 @@ bool MemoryFile::truncate(size_t size) { } if (!ftruncate(m_diskFile.getFd(), m_size)) { - MMKVError("fail to truncate [%ws] to size %zu", m_diskFile.m_path.c_str(), m_size); + MMKVError("fail to truncate [%ls] to size %zu", m_diskFile.m_path.c_str(), m_size); m_size = oldSize; return false; } if (m_size > oldSize) { if (!zeroFillFile(m_diskFile.getFd(), oldSize, m_size - oldSize)) { - MMKVError("fail to zeroFile [%ws] to size %zu", m_diskFile.m_path.c_str(), m_size); + MMKVError("fail to zeroFile [%ls] to size %zu", m_diskFile.m_path.c_str(), m_size); m_size = oldSize; return false; } @@ -132,7 +132,7 @@ bool MemoryFile::truncate(size_t size) { if (m_ptr) { if (!UnmapViewOfFile(m_ptr)) { - MMKVError("fail to munmap [%ws], %d", m_diskFile.m_path.c_str(), GetLastError()); + MMKVError("fail to munmap [%ls], %d", m_diskFile.m_path.c_str(), GetLastError()); } m_ptr = nullptr; } @@ -152,13 +152,13 @@ bool MemoryFile::msync(SyncFlag syncFlag) { if (FlushViewOfFile(m_ptr, m_size)) { if (syncFlag == MMKV_SYNC) { if (!FlushFileBuffers(m_diskFile.getFd())) { - MMKVError("fail to FlushFileBuffers [%ws]:%d", m_diskFile.m_path.c_str(), GetLastError()); + MMKVError("fail to FlushFileBuffers [%ls]:%d", m_diskFile.m_path.c_str(), GetLastError()); return false; } } return true; } - MMKVError("fail to FlushViewOfFile [%ws]:%d", m_diskFile.m_path.c_str(), GetLastError()); + MMKVError("fail to FlushViewOfFile [%ls]:%d", m_diskFile.m_path.c_str(), GetLastError()); return false; } return false; @@ -167,12 +167,12 @@ bool MemoryFile::msync(SyncFlag syncFlag) { bool MemoryFile::mmap() { m_fileMapping = CreateFileMapping(m_diskFile.getFd(), nullptr, PAGE_READWRITE, 0, 0, nullptr); if (!m_fileMapping) { - MMKVError("fail to CreateFileMapping [%ws], %d", m_diskFile.m_path.c_str(), GetLastError()); + MMKVError("fail to CreateFileMapping [%ls], %d", m_diskFile.m_path.c_str(), GetLastError()); return false; } else { m_ptr = (char *) MapViewOfFile(m_fileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (!m_ptr) { - MMKVError("fail to mmap [%ws], %d", m_diskFile.m_path.c_str(), GetLastError()); + MMKVError("fail to mmap [%ls], %d", m_diskFile.m_path.c_str(), GetLastError()); return false; } } @@ -182,7 +182,7 @@ bool MemoryFile::mmap() { void MemoryFile::reloadFromFile() { if (isFileValid()) { - MMKVWarning("calling reloadFromFile while the cache [%ws] is still valid", m_diskFile.m_path.c_str()); + MMKVWarning("calling reloadFromFile while the cache [%ls] is still valid", m_diskFile.m_path.c_str()); assert(0); clearMemoryCache(); } @@ -248,12 +248,12 @@ bool mkPath(const MMKVPath_t &str) { auto attribute = GetFileAttributes(path); if (attribute == INVALID_FILE_ATTRIBUTES) { if (!CreateDirectory(path, nullptr)) { - MMKVError("fail to create dir:%ws, %d", str.c_str(), GetLastError()); + MMKVError("fail to create dir:%ls, %d", str.c_str(), GetLastError()); free(path); return false; } } else if (!(attribute & FILE_ATTRIBUTE_DIRECTORY)) { - MMKVError("%ws attribute:%d not a directry", str.c_str(), attribute); + MMKVError("%ls attribute:%d not a directry", str.c_str(), attribute); free(path); return false; } @@ -279,14 +279,14 @@ MMBuffer *readWholeFile(const MMKVPath_t &nsFilePath) { if (ReadFile(fd, buffer->getPtr(), fileLength, &readSize, nullptr)) { //fileSize = readSize; } else { - MMKVWarning("fail to read %ws: %d", nsFilePath.c_str(), GetLastError()); + MMKVWarning("fail to read %ls: %d", nsFilePath.c_str(), GetLastError()); delete buffer; buffer = nullptr; } } CloseHandle(fd); } else { - MMKVWarning("fail to open %ws: %d", nsFilePath.c_str(), GetLastError()); + MMKVWarning("fail to open %ls: %d", nsFilePath.c_str(), GetLastError()); } return buffer; } @@ -365,16 +365,16 @@ static pair createUniqueTempFile(const wchar_t *pr } auto hTempFile = CreateFile(szTempFileName, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (hTempFile == INVALID_HANDLE_VALUE) { - MMKVError("fail to create unique temp file [%ws], %d", szTempFileName, GetLastError()); + MMKVError("fail to create unique temp file [%ls], %d", szTempFileName, GetLastError()); return {L"", INVALID_HANDLE_VALUE}; } - MMKVDebug("create unique temp file [%ws] with fd[%p]", szTempFileName, hTempFile); + MMKVDebug("create unique temp file [%ls] with fd[%p]", szTempFileName, hTempFile); return {MMKVPath_t(szTempFileName), hTempFile}; } bool tryAtomicRename(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) { if (MoveFileEx(srcPath.c_str(), dstPath.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) == 0) { - MMKVError("MoveFileEx [%ws] to [%ws] failed %d", srcPath.c_str(), dstPath.c_str(), GetLastError()); + MMKVError("MoveFileEx [%ls] to [%ls] failed %d", srcPath.c_str(), dstPath.c_str(), GetLastError()); return false; } return true; @@ -401,7 +401,7 @@ bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD, bool nee while (true) { DWORD sizeRead = 0; if (!ReadFile(srcFile.getFd(), buffer, bufferSize, &sizeRead, nullptr)) { - MMKVError("fail to read %ws: %d", srcPath.c_str(), GetLastError()); + MMKVError("fail to read %ls: %d", srcPath.c_str(), GetLastError()); goto errorOut; } @@ -426,7 +426,7 @@ bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD, bool nee } ret = true; - MMKVInfo("copy content from %ws to fd[%d] finish", srcPath.c_str(), dstFD); + MMKVInfo("copy content from %ls to fd[%d] finish", srcPath.c_str(), dstFD); errorOut: free(buffer); @@ -445,11 +445,11 @@ bool copyFile(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) { bool renamed = false; if (copyFileContent(srcPath, tmpFD, false)) { - MMKVInfo("copyed file [%ws] to [%ws]", srcPath.c_str(), tmpPath.c_str()); + MMKVInfo("copyed file [%ls] to [%ls]", srcPath.c_str(), tmpPath.c_str()); CloseHandle(tmpFD); renamed = tryAtomicRename(tmpPath.c_str(), dstPath.c_str()); if (renamed) { - MMKVInfo("copyfile [%ws] to [%ws] finish.", srcPath.c_str(), dstPath.c_str()); + MMKVInfo("copyfile [%ls] to [%ls] finish.", srcPath.c_str(), dstPath.c_str()); } } else { CloseHandle(tmpFD); @@ -468,9 +468,9 @@ bool copyFileContent(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) { } auto ret = copyFileContent(srcPath, dstFile.getFd(), false); if (!ret) { - MMKVError("fail to copyfile(): target file %ws", dstPath.c_str()); + MMKVError("fail to copyfile(): target file %ls", dstPath.c_str()); } else { - MMKVInfo("copy content from %ws to [%ws] finish", srcPath.c_str(), dstPath.c_str()); + MMKVInfo("copy content from %ls to [%ls] finish", srcPath.c_str(), dstPath.c_str()); } return ret; } diff --git a/Core/aes/AESCrypt.h b/Core/aes/AESCrypt.h old mode 100644 new mode 100755 index 0596f1c2..7a87301d --- a/Core/aes/AESCrypt.h +++ b/Core/aes/AESCrypt.h @@ -22,7 +22,7 @@ #define AES_CRYPT_H_ #ifdef __cplusplus -#include "MMKVPredef.h" +#include "../MMKVPredef.h" #include #ifdef MMKV_DISABLE_CRYPT diff --git a/MMKV.podspec b/MMKV.podspec index 29241a9c..805b243b 100644 --- a/MMKV.podspec +++ b/MMKV.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "MMKV" - s.version = "1.2.15" + s.version = "1.2.16" s.summary = "MMKV is a cross-platform key-value storage framework developed by WeChat." s.description = <<-DESC @@ -31,7 +31,7 @@ Pod::Spec.new do |s| "CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF" => "NO", } - s.dependency 'MMKVCore', '~> 1.2.15' + s.dependency 'MMKVCore', '~> 1.2.16' end diff --git a/MMKVAppExtension.podspec b/MMKVAppExtension.podspec index 27d65d6f..29466ee1 100644 --- a/MMKVAppExtension.podspec +++ b/MMKVAppExtension.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "MMKVAppExtension" - s.version = "1.2.15" + s.version = "1.2.16" s.summary = "MMKV is a cross-platform key-value storage framework developed by WeChat." s.module_name = "MMKVAppExtension" @@ -31,7 +31,7 @@ Pod::Spec.new do |s| "GCC_PREPROCESSOR_DEFINITIONS" => "MMKV_IOS_EXTENSION", } - s.dependency 'MMKVCore', '~> 1.2.15' + s.dependency 'MMKVCore', '~> 1.2.16' end diff --git a/MMKVCore.podspec b/MMKVCore.podspec index 591bff24..ce10ba84 100644 --- a/MMKVCore.podspec +++ b/MMKVCore.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "MMKVCore" - s.version = "1.2.15" + s.version = "1.2.16" s.summary = "MMKVCore for MMKV. MMKV is a cross-platform key-value storage framework developed by WeChat." s.description = <<-DESC diff --git a/MMKVWatchExtension.podspec b/MMKVWatchExtension.podspec index d161c1a8..093e71dd 100644 --- a/MMKVWatchExtension.podspec +++ b/MMKVWatchExtension.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "MMKVWatchExtension" - s.version = "1.2.15" + s.version = "1.2.16" s.summary = "MMKV is a cross-platform key-value storage framework developed by WeChat." s.module_name = "MMKVWatchExtension" @@ -31,7 +31,7 @@ Pod::Spec.new do |s| "GCC_PREPROCESSOR_DEFINITIONS" => "MMKV_IOS_EXTENSION", } - s.dependency 'MMKVCore', '~> 1.2.15' + s.dependency 'MMKVCore', '~> 1.2.16' end diff --git a/POSIX/golang/mmkv.go b/POSIX/golang/mmkv.go index 2b3c18ad..520f9aa4 100644 --- a/POSIX/golang/mmkv.go +++ b/POSIX/golang/mmkv.go @@ -52,6 +52,7 @@ static void freeStringArray(GoStringWrap_t *a, size_t size) { */ import "C" import "unsafe" +import "math" const ( MMKVLogDebug = iota // not available for release/product build @@ -205,12 +206,14 @@ func Version() string { return goStr } -/* MMKV must be initialized before any usage. - * Generally speaking you should do this inside main(): -func main() { - mmkv.InitializeMMKV("/path/to/my/working/dir") - // other logic -} +/* +MMKV must be initialized before any usage. +* Generally speaking you should do this inside main(): + + func main() { + mmkv.InitializeMMKV("/path/to/my/working/dir") + // other logic + } */ func InitializeMMKV(rootDir string) { C.mmkvInitialize(C.wrapGoString(rootDir), MMKVLogInfo, C.bool(false)) @@ -224,7 +227,7 @@ func InitializeMMKVWithLogLevel(rootDir string, logLevel int) { // Same as the function InitializeMMKVWithLogLevel() above, except that you can provide a logHandler at the very beginning. func InitializeMMKVWithLogLevelAndHandler(rootDir string, logLevel int, logHandler LogHandler) { - gLogHandler = logHandler + gLogHandler = logHandler C.mmkvInitialize(C.wrapGoString(rootDir), C.int32_t(logLevel), C.bool(true)) } @@ -470,7 +473,7 @@ func (kv ctorMMKV) AllKeys() []string { return []string{} } // turn C array into go slice with offset(0), length(count) & capacity(count) - keys := (*[1 << 30]C.struct_GoStringWrap)(unsafe.Pointer(keyArray))[0:count:count] + keys := (*[math.MaxInt32 / unsafe.Sizeof(C.struct_GoStringWrap{})]C.struct_GoStringWrap)(unsafe.Pointer(keyArray))[0:count:count] // Actually the keys IS a go string slice, but we need to COPY the elements for the caller to use. // Too bad go doesn't has destructors, hence we can't simply TRANSFER ownership of C memory. diff --git a/README.md b/README.md index cc059c54..a456d191 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![license](https://img.shields.io/badge/license-BSD_3-brightgreen.svg?style=flat)](https://github.com/Tencent/MMKV/blob/master/LICENSE.TXT) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Tencent/MMKV/pulls) -[![Release Version](https://img.shields.io/badge/release-1.2.15-brightgreen.svg)](https://github.com/Tencent/MMKV/releases) +[![Release Version](https://img.shields.io/badge/release-1.2.16-brightgreen.svg)](https://github.com/Tencent/MMKV/releases) [![Platform](https://img.shields.io/badge/Platform-%20Android%20%7C%20iOS%2FmacOS%20%7C%20Win32%20%7C%20POSIX-brightgreen.svg)](https://github.com/Tencent/MMKV/wiki/home) 中文版本请参看[这里](./README_CN.md) @@ -28,8 +28,8 @@ Add the following lines to `build.gradle` on your app module: ```gradle dependencies { - implementation 'com.tencent:mmkv:1.2.15' - // replace "1.2.15" with any available version + implementation 'com.tencent:mmkv:1.2.16' + // replace "1.2.16" with any available version } ``` diff --git a/README_CN.md b/README_CN.md index c203042f..97de4122 100644 --- a/README_CN.md +++ b/README_CN.md @@ -22,8 +22,8 @@ MMKV 是基于 mmap 内存映射的 key-value 组件,底层序列化/反序列 ```gradle dependencies { - implementation 'com.tencent:mmkv:1.2.15' - // replace "1.2.15" with any available version + implementation 'com.tencent:mmkv:1.2.16' + // replace "1.2.16" with any available version } ``` 从 v1.2.8 起, MMKV **迁移到 Maven Central**。 diff --git a/flutter/CHANGELOG.md b/flutter/CHANGELOG.md index ae826131..86cfc368 100644 --- a/flutter/CHANGELOG.md +++ b/flutter/CHANGELOG.md @@ -1,5 +1,13 @@ # MMKV for Flutter Change Log +## v1.2.17 / 2023-04-20 +* Optimization: The actual file content is lazy loaded now, saving time on MMKV instance creation, and avoiding lock waiting when a lot of instances are created at the same time. +* Fix a bug when restoring a loaded MMKV instance the meta file might mistakenly report corrupted. +* Fix a crash on decoding an empty list. +* Remove deprecated dependence. +* Make the script more robust to fix the iOS Flutter plugin name. +* Keep up with MMKV native lib v1.2.16. + ## v1.2.16 / 2023-01-12 * Reduce the privacy info needed to obtain android sdkInt, avoid unnecessary risk on Android App Review. * Log handler now handles all logs from the very beginning, especially the logs in initialization. diff --git a/flutter/README.md b/flutter/README.md index 18c4aa2c..4c0d647f 100644 --- a/flutter/README.md +++ b/flutter/README.md @@ -1,6 +1,6 @@ [![license](https://img.shields.io/badge/license-BSD_3-brightgreen.svg?style=flat)](https://github.com/Tencent/MMKV/blob/master/LICENSE.TXT) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Tencent/MMKV/pulls) -[![Release Version](https://img.shields.io/badge/release-1.2.16-brightgreen.svg)](https://github.com/Tencent/MMKV/releases) +[![Release Version](https://img.shields.io/badge/release-1.2.17-brightgreen.svg)](https://github.com/Tencent/MMKV/releases) [![Platform](https://img.shields.io/badge/Platform-%20Android%20%7C%20iOS-brightgreen.svg)](https://github.com/Tencent/MMKV/wiki/home) MMKV is an **efficient**, **small**, **easy-to-use** mobile key-value storage framework used in the WeChat application. It's currently available on **Android** and **iOS**. @@ -26,11 +26,11 @@ Add the following lines to `pubspec.yaml` on your app module. Then run `flutter ```yaml dependencies: - mmkv: ">=1.2.16" + mmkv: ">=1.2.17" ... ``` -If you already include MMKV native lib in your App, you need to upgrade to version newer than v1.2.15. +If you already include MMKV native lib in your App, you need to upgrade to version newer than v1.2.16. #### iOS To avoid conflict of the native lib name 'libMMKV.so' on iOS, we need to **change the plugin name 'mmkv' to 'mmkvflutter'**. diff --git a/flutter/analysis_options.yaml b/flutter/analysis_options.yaml new file mode 100644 index 00000000..81c4e24a --- /dev/null +++ b/flutter/analysis_options.yaml @@ -0,0 +1,48 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + errors: + invalid_annotation_target: ignore + exclude: + - "lib/assets.dart" + - "lib/injection.config.dart" + - "lib/**.g.dart" + - "lib/**.freeezed.dart" + - lib/jsons.dart + + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + prefer_double_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + always_use_package_imports: true + always_declare_return_types: true + always_put_required_named_parameters_first: true + avoid_unused_constructor_parameters: true + prefer_final_fields: true + prefer_final_in_for_each: true + prefer_final_locals: true + constant_identifier_names: false + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/flutter/example/android/app/src/main/AndroidManifest.xml b/flutter/example/android/app/src/main/AndroidManifest.xml index dd1fb5d0..fd4c98ad 100644 --- a/flutter/example/android/app/src/main/AndroidManifest.xml +++ b/flutter/example/android/app/src/main/AndroidManifest.xml @@ -5,6 +5,8 @@ In most cases you can leave this as-is, but you if you want to provide additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> + + - - + diff --git a/flutter/example/ios/Flutter/AppFrameworkInfo.plist b/flutter/example/ios/Flutter/AppFrameworkInfo.plist index f2872cf4..4f8d4d24 100644 --- a/flutter/example/ios/Flutter/AppFrameworkInfo.plist +++ b/flutter/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 9.0 + 11.0 diff --git a/flutter/example/ios/Podfile b/flutter/example/ios/Podfile index 5c91e17c..d55c0fab 100644 --- a/flutter/example/ios/Podfile +++ b/flutter/example/ios/Podfile @@ -1,9 +1,9 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '11.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' -platform :ios, '9.0' +platform :ios, '11.0' #source 'https://git.code.oa.com/guoling/PrivatePodSpec.git' @@ -28,11 +28,22 @@ end require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) +# from ruby 3.2 File.exists is broken, we need compat function +def mmkv_file_exists(file) + is_exist = false + if File.methods.include?(:exists?) + is_exist = File.exists? file + else + is_exist = File.exist? file + end + return is_exist +end + # to avoid conflict of the native lib name 'libMMKV.so' on iOS, we need to change the plugin name 'mmkv' to 'mmkvflutter' def fix_mmkv_plugin_name(flutter_application_path) is_module = false plugin_deps_file = File.expand_path(File.join(flutter_application_path, '..', '.flutter-plugins-dependencies')) - if not File.exists?(plugin_deps_file) + if not mmkv_file_exists(plugin_deps_file) is_module = true; plugin_deps_file = File.expand_path(File.join(flutter_application_path, '.flutter-plugins-dependencies')) end @@ -54,6 +65,9 @@ flutter_ios_podfile_setup target 'Runner' do flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + # https://github.com/Tencent/MMKV/issues/669 + # https://blog.cocoapods.org/CocoaPods-1.4.0/ + script_phase :name => 'Fix MMKV Plugin Name', :script => 'sed -i "" "s/@import mmkv;/@import mmkvflutter;/g" ${SRCROOT}/Runner/GeneratedPluginRegistrant.m', :execution_position=>:before_compile end post_install do |installer| diff --git a/flutter/example/ios/Podfile.lock b/flutter/example/ios/Podfile.lock index d9189533..bbd5eb62 100644 --- a/flutter/example/ios/Podfile.lock +++ b/flutter/example/ios/Podfile.lock @@ -1,18 +1,15 @@ PODS: - - device_info_plus (0.0.1): - - Flutter - Flutter (1.0.0) - - MMKV (1.2.14): - - MMKVCore (~> 1.2.14) - - MMKVCore (1.2.14) - - mmkvflutter (1.2.14): + - MMKV (1.2.15): + - MMKVCore (~> 1.2.15) + - MMKVCore (1.2.15) + - mmkvflutter (1.2.15): - Flutter - - MMKV (>= 1.2.14) + - MMKV (>= 1.2.15) - path_provider_ios (0.0.1): - Flutter DEPENDENCIES: - - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - Flutter (from `Flutter`) - mmkvflutter (from `.symlinks/plugins/mmkvflutter/ios`) - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) @@ -23,8 +20,6 @@ SPEC REPOS: - MMKVCore EXTERNAL SOURCES: - device_info_plus: - :path: ".symlinks/plugins/device_info_plus/ios" Flutter: :path: Flutter mmkvflutter: @@ -33,13 +28,12 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/path_provider_ios/ios" SPEC CHECKSUMS: - device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a - MMKV: 9c4663aa7ca255d478ff10f2f5cb7d17c1651ccd - MMKVCore: 89f5c8a66bba2dcd551779dea4d412eeec8ff5bb - mmkvflutter: 325713a470a4015625dfd829070745c5ca852df6 + MMKV: 7f34558bbb5a33b0eaefae2de4b6a20a2ffdad6f + MMKVCore: ddf41b9d9262f058419f9ba7598719af56c02cd3 + mmkvflutter: adff7ed724316d0cea22d65b59f43d467fc57403 path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 -PODFILE CHECKSUM: 5892152591d599b8a50589fd8872b0421e2fc7b5 +PODFILE CHECKSUM: 751e522a1d35e86af4f588d982f4a515941611c5 COCOAPODS: 1.11.2 diff --git a/flutter/example/ios/Runner.xcodeproj/project.pbxproj b/flutter/example/ios/Runner.xcodeproj/project.pbxproj index 2c13765d..ac062d52 100644 --- a/flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -146,6 +146,7 @@ buildPhases = ( 19FB7C13A6F154DB79BFE09E /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, + DBADF7DE4086731B8B058FA4 /* [CP-User] Fix MMKV Plugin Name */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, @@ -167,7 +168,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; + LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -258,6 +259,16 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; }; + DBADF7DE4086731B8B058FA4 /* [CP-User] Fix MMKV Plugin Name */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + name = "[CP-User] Fix MMKV Plugin Name"; + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "sed -i \"\" \"s/@import mmkv;/@import mmkvflutter;/g\" ${SRCROOT}/Runner/GeneratedPluginRegistrant.m"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -334,7 +345,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -423,7 +434,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -472,7 +483,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/flutter/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/flutter/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16..919434a6 100644 --- a/flutter/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/flutter/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index fb2dffc4..c87d15a3 100644 --- a/flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ UIViewControllerBasedStatusBarAppearance + CADisableMinimumFrameDurationOnPhone + diff --git a/flutter/example/lib/main.dart b/flutter/example/lib/main.dart index bcf3167c..99d0c41e 100644 --- a/flutter/example/lib/main.dart +++ b/flutter/example/lib/main.dart @@ -18,17 +18,18 @@ * limitations under the License. */ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; +import "dart:async"; +import "dart:convert"; +import "dart:io"; +import "dart:typed_data"; -import 'package:flutter/material.dart'; -import 'package:mmkv/mmkv.dart'; +import "package:flutter/material.dart"; +import "package:mmkv/mmkv.dart"; void main() async { // must wait for MMKV to finish initialization final rootDir = await MMKV.initialize(); - print('MMKV for flutter with rootDir = $rootDir'); + print("MMKV for flutter with rootDir = $rootDir"); runApp(MyApp()); } @@ -60,27 +61,27 @@ class _MyAppState extends State { return MaterialApp( home: Scaffold( appBar: AppBar( - title: const Text('MMKV Plugin example app'), + title: const Text("MMKV Plugin example app"), ), body: Center( child: Column(children: [ - Text('MMKV Version: ${MMKV.version}\n'), + Text("MMKV Version: ${MMKV.version}\n"), TextButton( onPressed: () { functionalTest(); }, - child: Text('Functional Test', style: TextStyle(fontSize: 18))), + child: Text("Functional Test", style: TextStyle(fontSize: 18))), TextButton( onPressed: () { testReKey(); }, - child: Text('Encryption Test', style: TextStyle(fontSize: 18))), + child: Text("Encryption Test", style: TextStyle(fontSize: 18))), TextButton( onPressed: () { testBackup(); testRestore(); }, - child: Text('Backup & Restore Test', + child: Text("Backup & Restore Test", style: TextStyle(fontSize: 18))), ])), ), @@ -92,59 +93,81 @@ class _MyAppState extends State { * you can try passing this encryption key '\u{2}U' instead. * var mmkv = MMKV.defaultMMKV(cryptKey: '\u{2}U'); */ - var mmkv = MMKV.defaultMMKV(); - mmkv.encodeBool('bool', true); + final mmkv = MMKV.defaultMMKV(); + mmkv.encodeBool("bool", true); print('bool = ${mmkv.decodeBool('bool')}'); - mmkv.encodeInt32('int32', (1 << 31) - 1); + mmkv.encodeInt32("int32", (1 << 31) - 1); print('max int32 = ${mmkv.decodeInt32('int32')}'); - mmkv.encodeInt32('int32', 0 - (1 << 31)); + mmkv.encodeInt32("int32", 0 - (1 << 31)); print('min int32 = ${mmkv.decodeInt32('int32')}'); - mmkv.encodeInt('int', (1 << 63) - 1); + mmkv.encodeInt("int", (1 << 63) - 1); print('max int = ${mmkv.decodeInt('int')}'); - mmkv.encodeInt('int', 0 - (1 << 63)); + mmkv.encodeInt("int", 0 - (1 << 63)); print('min int = ${mmkv.decodeInt('int')}'); - mmkv.encodeDouble('double', double.maxFinite); + mmkv.encodeDouble("double", double.maxFinite); print('max double = ${mmkv.decodeDouble('double')}'); - mmkv.encodeDouble('double', double.minPositive); + mmkv.encodeDouble("double", double.minPositive); print('min positive double = ${mmkv.decodeDouble('double')}'); - String str = 'Hello dart from MMKV'; - mmkv.encodeString('string', str); + String str = "Hello dart from MMKV"; + mmkv.encodeString("string", str); print('string = ${mmkv.decodeString('string')}'); - mmkv.encodeString('string', ''); + mmkv.encodeString("string", ""); print('empty string = ${mmkv.decodeString('string')}'); print('contains "string": ${mmkv.containsKey('string')}'); - mmkv.encodeString('string', null); + mmkv.encodeString("string", null); print('null string = ${mmkv.decodeString('string')}'); print('contains "string": ${mmkv.containsKey('string')}'); - str += ' with bytes'; + str += " with bytes"; var bytes = MMBuffer.fromList(Utf8Encoder().convert(str))!; - mmkv.encodeBytes('bytes', bytes); + mmkv.encodeBytes("bytes", bytes); bytes.destroy(); - bytes = mmkv.decodeBytes('bytes')!; - print('bytes = ${Utf8Decoder().convert(bytes.asList()!)}'); + bytes = mmkv.decodeBytes("bytes")!; + print("bytes = ${Utf8Decoder().convert(bytes.asList()!)}"); bytes.destroy(); + // test empty bytes + { + final list = Uint8List(0); + final buffer = MMBuffer.fromList(list)!; + + const key = "empty_bytes"; + mmkv.encodeBytes(key, buffer); + buffer.destroy(); + + String bytesA; + final result = mmkv.decodeBytes(key); + if (result == null) { + bytesA = "decodeBytes is null"; + } else { + // bytes = result.takeList().toString(); + final listA = result.asList(); + bytesA = listA.toString(); + result.destroy(); + } + print("$key = $bytesA"); + } + print('contains "bool": ${mmkv.containsKey('bool')}'); - mmkv.removeValue('bool'); + mmkv.removeValue("bool"); print('after remove, contains "bool": ${mmkv.containsKey('bool')}'); - mmkv.removeValues(['int32', 'int']); - print('all keys: ${mmkv.allKeys}'); + mmkv.removeValues(["int32", "int"]); + print("all keys: ${mmkv.allKeys}"); mmkv.trim(); mmkv.clearMemoryCache(); - print('all keys: ${mmkv.allKeys}'); + print("all keys: ${mmkv.allKeys}"); mmkv.clearAll(); - print('all keys: ${mmkv.allKeys}'); + print("all keys: ${mmkv.allKeys}"); // mmkv.sync(true); // mmkv.close(); } @@ -154,76 +177,76 @@ class _MyAppState extends State { final mmkv = MMKV(mmapID, cryptKey: cryptKey, rootDir: rootPath); if (!decodeOnly) { - mmkv.encodeBool('bool', true); + mmkv.encodeBool("bool", true); } print('bool = ${mmkv.decodeBool('bool')}'); if (!decodeOnly) { - mmkv.encodeInt32('int32', (1 << 31) - 1); + mmkv.encodeInt32("int32", (1 << 31) - 1); } print('max int32 = ${mmkv.decodeInt32('int32')}'); if (!decodeOnly) { - mmkv.encodeInt32('int32', 0 - (1 << 31)); + mmkv.encodeInt32("int32", 0 - (1 << 31)); } print('min int32 = ${mmkv.decodeInt32('int32')}'); if (!decodeOnly) { - mmkv.encodeInt('int', (1 << 63) - 1); + mmkv.encodeInt("int", (1 << 63) - 1); } print('max int = ${mmkv.decodeInt('int')}'); if (!decodeOnly) { - mmkv.encodeInt('int', 0 - (1 << 63)); + mmkv.encodeInt("int", 0 - (1 << 63)); } print('min int = ${mmkv.decodeInt('int')}'); if (!decodeOnly) { - mmkv.encodeDouble('double', double.maxFinite); + mmkv.encodeDouble("double", double.maxFinite); } print('max double = ${mmkv.decodeDouble('double')}'); if (!decodeOnly) { - mmkv.encodeDouble('double', double.minPositive); + mmkv.encodeDouble("double", double.minPositive); } print('min positive double = ${mmkv.decodeDouble('double')}'); - String str = 'Hello dart from MMKV'; + String str = "Hello dart from MMKV"; if (!decodeOnly) { - mmkv.encodeString('string', str); + mmkv.encodeString("string", str); } print('string = ${mmkv.decodeString('string')}'); - str += ' with bytes'; + str += " with bytes"; var bytes = MMBuffer.fromList(Utf8Encoder().convert(str))!; if (!decodeOnly) { - mmkv.encodeBytes('bytes', bytes); + mmkv.encodeBytes("bytes", bytes); } bytes.destroy(); - bytes = mmkv.decodeBytes('bytes')!; - print('bytes = ${Utf8Decoder().convert(bytes.asList()!)}'); + bytes = mmkv.decodeBytes("bytes")!; + print("bytes = ${Utf8Decoder().convert(bytes.asList()!)}"); bytes.destroy(); print('contains "bool": ${mmkv.containsKey('bool')}'); - mmkv.removeValue('bool'); + mmkv.removeValue("bool"); print('after remove, contains "bool": ${mmkv.containsKey('bool')}'); - mmkv.removeValues(['int32', 'int']); - print('all keys: ${mmkv.allKeys}'); + mmkv.removeValues(["int32", "int"]); + print("all keys: ${mmkv.allKeys}"); return mmkv; } void testReKey() { - final mmapID = 'testAES_reKey1'; - MMKV kv = testMMKV(mmapID, null, false, null); + final mmapID = "testAES_reKey1"; + final MMKV kv = testMMKV(mmapID, null, false, null); kv.reKey("Key_seq_1"); kv.clearMemoryCache(); - testMMKV(mmapID, 'Key_seq_1', true, null); + testMMKV(mmapID, "Key_seq_1", true, null); - kv.reKey('Key_seq_2'); + kv.reKey("Key_seq_2"); kv.clearMemoryCache(); - testMMKV(mmapID, 'Key_seq_2', true, null); + testMMKV(mmapID, "Key_seq_2", true, null); kv.reKey(null); kv.clearMemoryCache(); @@ -233,13 +256,14 @@ class _MyAppState extends State { void testBackup() { final rootDir = FileSystemEntity.parentOf(MMKV.rootDir); var backupRootDir = rootDir + "/mmkv_backup_3"; - String mmapID = "test/AES"; - String cryptKey = "Tencent MMKV"; - String otherDir = rootDir + "/mmkv_3"; + final String mmapID = "test/AES"; + final String cryptKey = "Tencent MMKV"; + final String otherDir = rootDir + "/mmkv_3"; testMMKV(mmapID, cryptKey, false, otherDir); - final ret = MMKV.backupOneToDirectory(mmapID, backupRootDir, rootDir: otherDir); - print('backup one [$mmapID] return: $ret'); + final ret = + MMKV.backupOneToDirectory(mmapID, backupRootDir, rootDir: otherDir); + print("backup one [$mmapID] return: $ret"); backupRootDir = rootDir + "/mmkv_backup"; final count = MMKV.backupAllToDirectory(backupRootDir); @@ -249,15 +273,15 @@ class _MyAppState extends State { void testRestore() { final rootDir = FileSystemEntity.parentOf(MMKV.rootDir); var backupRootDir = rootDir + "/mmkv_backup_3"; - String mmapID = "test/AES"; - String cryptKey = "Tencent MMKV"; - String otherDir = rootDir + "/mmkv_3"; + final String mmapID = "test/AES"; + final String cryptKey = "Tencent MMKV"; + final String otherDir = rootDir + "/mmkv_3"; final kv = MMKV(mmapID, cryptKey: cryptKey, rootDir: otherDir); - kv.encodeString('test_restore', 'value before restore'); + kv.encodeString("test_restore", "value before restore"); print("before restore [${kv.mmapID}] allKeys: ${kv.allKeys}"); - final ret = MMKV.restoreOneMMKVFromDirectory( - mmapID, backupRootDir, rootDir: otherDir); + final ret = MMKV.restoreOneMMKVFromDirectory(mmapID, backupRootDir, + rootDir: otherDir); print("restore one [${kv.mmapID}] ret = $ret"); if (ret) { print("after restore [${kv.mmapID}] allKeys: ${kv.allKeys}"); @@ -270,7 +294,7 @@ class _MyAppState extends State { var mmkv = MMKV.defaultMMKV(); print("check on restore file[${mmkv.mmapID}] allKeys: ${mmkv.allKeys}"); - mmkv = MMKV('testAES_reKey1'); + mmkv = MMKV("testAES_reKey1"); print("check on restore file[${mmkv.mmapID}] allKeys: ${mmkv.allKeys}"); } } diff --git a/flutter/example/pubspec.lock b/flutter/example/pubspec.lock index 353b40a8..0208d4f6 100644 --- a/flutter/example/pubspec.lock +++ b/flutter/example/pubspec.lock @@ -50,48 +50,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.5" - device_info_plus: - dependency: transitive - description: - name: device_info_plus - url: "https://pub.dartlang.org" - source: hosted - version: "4.1.3" - device_info_plus_linux: - dependency: transitive - description: - name: device_info_plus_linux - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - device_info_plus_macos: - dependency: transitive - description: - name: device_info_plus_macos - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - device_info_plus_platform_interface: - dependency: transitive - description: - name: device_info_plus_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - device_info_plus_web: - dependency: transitive - description: - name: device_info_plus_web - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - device_info_plus_windows: - dependency: transitive - description: - name: device_info_plus_windows - url: "https://pub.dartlang.org" - source: hosted - version: "4.1.0" fake_async: dependency: transitive description: @@ -123,18 +81,6 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.4" matcher: dependency: transitive description: diff --git a/flutter/lib/mmkv.dart b/flutter/lib/mmkv.dart index 74b25202..a382f240 100644 --- a/flutter/lib/mmkv.dart +++ b/flutter/lib/mmkv.dart @@ -18,17 +18,17 @@ * limitations under the License. */ -import 'dart:async'; -import 'dart:convert'; -import 'dart:ffi'; // For FFI -import 'dart:io'; // For Platform.isX -import 'dart:typed_data'; - -import 'package:ffi/ffi.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:path_provider/path_provider.dart'; +import "dart:async"; +import "dart:convert"; +import "dart:ffi"; // For FFI +import "dart:io"; // For Platform.isX +import "dart:typed_data"; + +import "package:ffi/ffi.dart"; +import "package:flutter/cupertino.dart"; +import "package:flutter/material.dart"; +import "package:flutter/services.dart"; +import "package:path_provider/path_provider.dart"; /// Log level for MMKV. enum MMKVLogLevel { Debug, Info, Warning, Error, None } @@ -68,8 +68,8 @@ class MMBuffer { return null; } - var buffer = MMBuffer(list.length); - if (list.length == 0) { + final buffer = MMBuffer(list.length); + if (list.isEmpty) { buffer._ptr = malloc(); } buffer.asList()!.setAll(0, list); @@ -79,7 +79,7 @@ class MMBuffer { /// Create a wrapper of native pointer [ptr] with size [length]. /// DON'T [destroy()] the result because it's not a copy. static MMBuffer _fromPointer(Pointer ptr, int length) { - var buffer = MMBuffer(0); + final buffer = MMBuffer(0); buffer._length = length; buffer._ptr = ptr; return buffer; @@ -88,8 +88,11 @@ class MMBuffer { /// Create a wrapper of native pointer [ptr] with size [length]. /// DO remember to [destroy()] the result because it's a COPY. static MMBuffer _copyFromPointer(Pointer ptr, int length) { - var buffer = MMBuffer(length); + final buffer = MMBuffer(length); buffer._length = length; + if (length == 0 && ptr != nullptr) { + buffer._ptr = malloc(); + } _memcpy(buffer.pointer!.cast(), ptr.cast(), length); return buffer; } @@ -116,7 +119,7 @@ class MMBuffer { /// And [destroy()] itself at the same time. Uint8List? takeList() { if (_ptr != null && _ptr != nullptr) { - var list = Uint8List.fromList(asList()!); + final list = Uint8List.fromList(asList()!); destroy(); return list; } @@ -130,7 +133,7 @@ class MMKV { Pointer _handle = nullptr; static String _rootDir = ""; - static const MethodChannel _channel = const MethodChannel('mmkv'); + static const MethodChannel _channel = MethodChannel("mmkv"); /// MMKV must be initialized before any usage. /// @@ -158,23 +161,23 @@ class MMKV { if (rootDir == null) { final path = await getApplicationDocumentsDirectory(); - rootDir = path.path + '/mmkv'; + rootDir = "${path.path}/mmkv"; } _rootDir = rootDir; if (Platform.isIOS) { final Map params = { - 'rootDir': rootDir, - 'logLevel': logLevel.index, + "rootDir": rootDir, + "logLevel": logLevel.index, }; if (groupDir != null) { - params['groupDir'] = groupDir; + params["groupDir"] = groupDir; } - final ret = await _channel.invokeMethod('initializeMMKV', params); + final ret = await _channel.invokeMethod("initializeMMKV", params); return ret; } else { final rootDirPtr = _string2Pointer(rootDir); - final sdkInt = await _channel.invokeMethod('getSdkVersion') ?? 0; + final sdkInt = await _channel.invokeMethod("getSdkVersion") ?? 0; final cacheDir = await getTemporaryDirectory(); final cacheDirPtr = _string2Pointer(cacheDir.path); @@ -199,9 +202,9 @@ class MMKV { /// var mmkv = MMKV.defaultMMKV(cryptKey: '\u{2}U'); /// ``` static MMKV defaultMMKV({String? cryptKey}) { - var mmkv = MMKV(""); + final mmkv = MMKV(""); final cryptKeyPtr = _string2Pointer(cryptKey); - final mode = MMKVMode.SINGLE_PROCESS_MODE; + const mode = MMKVMode.SINGLE_PROCESS_MODE; mmkv._handle = _getDefaultMMKV(mode.index, cryptKeyPtr); calloc.free(cryptKeyPtr); return mmkv; @@ -235,15 +238,15 @@ class MMKV { } bool encodeBool(String key, bool value) { - var keyPtr = key.toNativeUtf8(); - var ret = _encodeBool(_handle, keyPtr, _bool2Int(value)); + final keyPtr = key.toNativeUtf8(); + final ret = _encodeBool(_handle, keyPtr, _bool2Int(value)); calloc.free(keyPtr); return _int2Bool(ret); } bool decodeBool(String key, {bool defaultValue = false}) { - var keyPtr = key.toNativeUtf8(); - var ret = _decodeBool(_handle, keyPtr, _bool2Int(defaultValue)); + final keyPtr = key.toNativeUtf8(); + final ret = _decodeBool(_handle, keyPtr, _bool2Int(defaultValue)); calloc.free(keyPtr); return _int2Bool(ret); } @@ -251,8 +254,8 @@ class MMKV { /// Use this when the [value] won't be larger than a normal int32. /// It's more efficient & cost less space. bool encodeInt32(String key, int value) { - var keyPtr = key.toNativeUtf8(); - var ret = _encodeInt32(_handle, keyPtr, value); + final keyPtr = key.toNativeUtf8(); + final ret = _encodeInt32(_handle, keyPtr, value); calloc.free(keyPtr); return _int2Bool(ret); } @@ -260,36 +263,36 @@ class MMKV { /// Use this when the value won't be larger than a normal int32. /// It's more efficient & cost less space. int decodeInt32(String key, {int defaultValue = 0}) { - var keyPtr = key.toNativeUtf8(); - var ret = _decodeInt32(_handle, keyPtr, defaultValue); + final keyPtr = key.toNativeUtf8(); + final ret = _decodeInt32(_handle, keyPtr, defaultValue); calloc.free(keyPtr); return ret; } bool encodeInt(String key, int value) { - var keyPtr = key.toNativeUtf8(); - var ret = _encodeInt64(_handle, keyPtr, value); + final keyPtr = key.toNativeUtf8(); + final ret = _encodeInt64(_handle, keyPtr, value); calloc.free(keyPtr); return _int2Bool(ret); } int decodeInt(String key, {int defaultValue = 0}) { - var keyPtr = key.toNativeUtf8(); - var ret = _decodeInt64(_handle, keyPtr, defaultValue); + final keyPtr = key.toNativeUtf8(); + final ret = _decodeInt64(_handle, keyPtr, defaultValue); calloc.free(keyPtr); return ret; } bool encodeDouble(String key, double value) { - var keyPtr = key.toNativeUtf8(); - var ret = _encodeDouble(_handle, keyPtr, value); + final keyPtr = key.toNativeUtf8(); + final ret = _encodeDouble(_handle, keyPtr, value); calloc.free(keyPtr); return _int2Bool(ret); } double decodeDouble(String key, {double defaultValue = 0}) { - var keyPtr = key.toNativeUtf8(); - var ret = _decodeDouble(_handle, keyPtr, defaultValue); + final keyPtr = key.toNativeUtf8(); + final ret = _decodeDouble(_handle, keyPtr, defaultValue); calloc.free(keyPtr); return ret; } @@ -302,9 +305,9 @@ class MMKV { } final keyPtr = key.toNativeUtf8(); - final bytes = MMBuffer.fromList(Utf8Encoder().convert(value))!; + final bytes = MMBuffer.fromList(const Utf8Encoder().convert(value))!; - var ret = _encodeBytes(_handle, keyPtr, bytes.pointer!, bytes.length); + final ret = _encodeBytes(_handle, keyPtr, bytes.pointer!, bytes.length); calloc.free(keyPtr); bytes.destroy(); @@ -313,16 +316,16 @@ class MMKV { /// Decode as an utf-8 string. String? decodeString(String key) { - var keyPtr = key.toNativeUtf8(); + final keyPtr = key.toNativeUtf8(); final lengthPtr = calloc(); - var ret = _decodeBytes(_handle, keyPtr, lengthPtr); + final ret = _decodeBytes(_handle, keyPtr, lengthPtr); calloc.free(keyPtr); if (ret != nullptr) { - var length = lengthPtr.value; + final length = lengthPtr.value; calloc.free(lengthPtr); - var result = _buffer2String(ret, length); + final result = _buffer2String(ret, length); if (!Platform.isIOS && length > 0) { calloc.free(ret); } @@ -351,8 +354,8 @@ class MMKV { return true; } - var keyPtr = key.toNativeUtf8(); - var ret = _encodeBytes(_handle, keyPtr, value.pointer!, value.length); + final keyPtr = key.toNativeUtf8(); + final ret = _encodeBytes(_handle, keyPtr, value.pointer!, value.length); calloc.free(keyPtr); return _int2Bool(ret); } @@ -372,16 +375,16 @@ class MMKV { /// } /// ``` MMBuffer? decodeBytes(String key) { - var keyPtr = key.toNativeUtf8(); + final keyPtr = key.toNativeUtf8(); final lengthPtr = calloc(); - var ret = _decodeBytes(_handle, keyPtr, lengthPtr); + final ret = _decodeBytes(_handle, keyPtr, lengthPtr); calloc.free(keyPtr); if (/*ret != null && */ ret != nullptr) { - var length = lengthPtr.value; + final length = lengthPtr.value; calloc.free(lengthPtr); - if (Platform.isIOS) { + if (Platform.isIOS || length == 0) { return MMBuffer._copyFromPointer(ret, length); } else { return MMBuffer._fromPointer(ret, length); @@ -398,13 +401,13 @@ class MMKV { /// * Or vice versa by passing [cryptKey] with null. /// See also [checkReSetCryptKey()]. bool reKey(String? cryptKey) { - if (cryptKey != null && cryptKey.length > 0) { - var bytes = MMBuffer.fromList(Utf8Encoder().convert(cryptKey))!; - var ret = _reKey(_handle, bytes.pointer!, bytes.length); + if (cryptKey != null && cryptKey.isNotEmpty) { + final bytes = MMBuffer.fromList(const Utf8Encoder().convert(cryptKey))!; + final ret = _reKey(_handle, bytes.pointer!, bytes.length); bytes.destroy(); return _int2Bool(ret); } else { - var ret = _reKey(_handle, nullptr, 0); + final ret = _reKey(_handle, nullptr, 0); return _int2Bool(ret); } } @@ -412,11 +415,11 @@ class MMKV { /// See also [reKey()]. String? get cryptKey { final lengthPtr = calloc(); - var ret = _cryptKey(_handle, lengthPtr); + final ret = _cryptKey(_handle, lengthPtr); if (/*ret != null && */ ret != nullptr) { - var length = lengthPtr.value; + final length = lengthPtr.value; calloc.free(lengthPtr); - var result = _buffer2String(ret, length); + final result = _buffer2String(ret, length); calloc.free(ret); return result; } @@ -426,7 +429,7 @@ class MMKV { /// Just reset the [cryptKey] (will not encrypt or decrypt anything). /// Usually you should call this method after other process [reKey()] the multi-process mmkv. void checkReSetCryptKey(String cryptKey) { - var bytes = MMBuffer.fromList(Utf8Encoder().convert(cryptKey))!; + final bytes = MMBuffer.fromList(const Utf8Encoder().convert(cryptKey))!; _checkReSetCryptKey(_handle, bytes.pointer!, bytes.length); bytes.destroy(); } @@ -434,8 +437,8 @@ class MMKV { /// Get the actual size consumption of the key's value. /// Pass [actualSize] with true to get value's length. int valueSize(String key, bool actualSize) { - var keyPtr = key.toNativeUtf8(); - var ret = _valueSize(_handle, keyPtr, _bool2Int(actualSize)); + final keyPtr = key.toNativeUtf8(); + final ret = _valueSize(_handle, keyPtr, _bool2Int(actualSize)); calloc.free(keyPtr); return ret; } @@ -445,8 +448,8 @@ class MMKV { /// * Return size written into buffer. /// * Return -1 on any error, such as [buffer] not large enough. int writeValueToNativeBuffer(String key, MMBuffer buffer) { - var keyPtr = key.toNativeUtf8(); - var ret = + final keyPtr = key.toNativeUtf8(); + final ret = _writeValueToNB(_handle, keyPtr, buffer.pointer!.cast(), buffer.length); calloc.free(keyPtr); return ret; @@ -456,7 +459,7 @@ class MMKV { List get allKeys { final keyArrayPtr = calloc>>(); final sizeArrayPtr = calloc>(); - List keys = []; + final List keys = []; final count = _allKeys(_handle, keyArrayPtr, sizeArrayPtr); if (count > 0) { @@ -484,8 +487,8 @@ class MMKV { } bool containsKey(String key) { - var keyPtr = key.toNativeUtf8(); - var ret = _containsKey(_handle, keyPtr); + final keyPtr = key.toNativeUtf8(); + final ret = _containsKey(_handle, keyPtr); calloc.free(keyPtr); return _int2Bool(ret); } @@ -505,7 +508,7 @@ class MMKV { } void removeValue(String key) { - var keyPtr = key.toNativeUtf8(); + final keyPtr = key.toNativeUtf8(); _removeValueForKey(_handle, keyPtr); calloc.free(keyPtr); } @@ -515,11 +518,11 @@ class MMKV { if (keys.isEmpty) { return; } - Pointer> keyArray = calloc>(keys.length); - Pointer sizeArray = malloc(keys.length); + final Pointer> keyArray = calloc>(keys.length); + final Pointer sizeArray = malloc(keys.length); for (int index = 0; index < keys.length; index++) { final key = keys[index]; - var bytes = MMBuffer.fromList(Utf8Encoder().convert(key))!; + final bytes = MMBuffer.fromList(const Utf8Encoder().convert(key))!; sizeArray[index] = bytes.length; keyArray[index] = bytes.pointer!.cast(); } @@ -580,11 +583,11 @@ class MMKV { /// * [rootDir] the customize root path of the MMKV, if null then backup from the root dir of MMKV static bool backupOneToDirectory(String mmapID, String dstDir, {String? rootDir}) { - var mmapIDPtr = mmapID.toNativeUtf8(); - var dstDirPtr = dstDir.toNativeUtf8(); - var rootDirPtr = _string2Pointer(rootDir); + final mmapIDPtr = mmapID.toNativeUtf8(); + final dstDirPtr = dstDir.toNativeUtf8(); + final rootDirPtr = _string2Pointer(rootDir); - var ret = _backupOne(mmapIDPtr, dstDirPtr, rootDirPtr); + final ret = _backupOne(mmapIDPtr, dstDirPtr, rootDirPtr); calloc.free(mmapIDPtr); calloc.free(dstDirPtr); @@ -598,11 +601,11 @@ class MMKV { /// * [rootDir] the customize root path of the MMKV, if null then restore to the root dir of MMKV static bool restoreOneMMKVFromDirectory(String mmapID, String srcDir, {String? rootDir}) { - var mmapIDPtr = mmapID.toNativeUtf8(); - var srcDirPtr = srcDir.toNativeUtf8(); - var rootDirPtr = _string2Pointer(rootDir); + final mmapIDPtr = mmapID.toNativeUtf8(); + final srcDirPtr = srcDir.toNativeUtf8(); + final rootDirPtr = _string2Pointer(rootDir); - var ret = _restoreOne(mmapIDPtr, srcDirPtr, rootDirPtr); + final ret = _restoreOne(mmapIDPtr, srcDirPtr, rootDirPtr); calloc.free(mmapIDPtr); calloc.free(srcDirPtr); @@ -613,9 +616,9 @@ class MMKV { /// backup all MMKV instance to [dstDir] static int backupAllToDirectory(String dstDir) { - var dstDirPtr = dstDir.toNativeUtf8(); + final dstDirPtr = dstDir.toNativeUtf8(); - var ret = _backupAll(dstDirPtr); + final ret = _backupAll(dstDirPtr); calloc.free(dstDirPtr); @@ -624,9 +627,9 @@ class MMKV { /// restore all MMKV instance from [srcDir] static int restoreAllFromDirectory(String srcDir) { - var srcDirPtr = srcDir.toNativeUtf8(); + final srcDirPtr = srcDir.toNativeUtf8(); - var ret = _restoreAll(srcDirPtr); + final ret = _restoreAll(srcDirPtr); calloc.free(srcDirPtr); @@ -718,8 +721,8 @@ String? _pointer2String(Pointer? ptr) { String? _buffer2String(Pointer? ptr, int length) { if (ptr != null && ptr != nullptr) { - var listView = ptr.asTypedList(length); - return Utf8Decoder().convert(listView); + final listView = ptr.asTypedList(length); + return const Utf8Decoder().convert(listView); } return null; } @@ -728,7 +731,7 @@ String _nativeFuncName(String name) { if (!Platform.isIOS) { return name; } - return "mmkv_" + name; + return "mmkv_$name"; } final DynamicLibrary _nativeLib = Platform.isAndroid diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index e957f5dc..ac869174 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -85,48 +85,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.2" - device_info_plus: - dependency: "direct main" - description: - name: device_info_plus - url: "https://pub.dartlang.org" - source: hosted - version: "4.1.3" - device_info_plus_linux: - dependency: transitive - description: - name: device_info_plus_linux - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - device_info_plus_macos: - dependency: transitive - description: - name: device_info_plus_macos - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - device_info_plus_platform_interface: - dependency: transitive - description: - name: device_info_plus_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - device_info_plus_web: - dependency: transitive - description: - name: device_info_plus_web - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - device_info_plus_windows: - dependency: transitive - description: - name: device_info_plus_windows - url: "https://pub.dartlang.org" - source: hosted - version: "4.1.0" fake_async: dependency: transitive description: @@ -153,16 +111,18 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" frontend_server_client: dependency: transitive description: @@ -205,6 +165,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.4" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" logging: dependency: transitive description: diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index 292b05fd..13ab68a5 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: mmkv description: An efficient, small mobile key-value storage framework developed by WeChat. Works on Android, iOS, macOS, Windows, and POSIX. -version: 1.2.16 +version: 1.2.17 homepage: https://github.com/Tencent/mmkv environment: @@ -12,12 +12,12 @@ dependencies: sdk: flutter path_provider: ^2.0.1 ffi: ^2.0.0 - device_info_plus: ^4.0.0 dev_dependencies: test: flutter_test: sdk: flutter + flutter_lints: ^2.0.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/flutter/test/mmkv_test.dart b/flutter/test/mmkv_test.dart index bd135842..fd209bd9 100644 --- a/flutter/test/mmkv_test.dart +++ b/flutter/test/mmkv_test.dart @@ -18,15 +18,31 @@ * limitations under the License. */ -import 'package:test/test.dart'; -import 'package:mmkv/mmkv.dart'; +import "package:mmkv/mmkv.dart"; +import "package:test/test.dart"; void main() { - test('Counter value should be incremented', () { + test("Int value should be written and read", () { final mmkv = MMKV.defaultMMKV(); mmkv.encodeInt("int", 1024); expect(mmkv.decodeInt("int"), 1024); }); -} \ No newline at end of file + + test("String value should be written and read", () { + final mmkv = MMKV.defaultMMKV(); + + mmkv.encodeString("string", "test"); + + expect(mmkv.decodeInt("string"), "test"); + }); + + test("bool value should be written and read", () { + final mmkv = MMKV.defaultMMKV(); + + mmkv.encodeBool("bool", true); + + expect(mmkv.decodeBool("bool"), true); + }); +} diff --git a/flutter/tool/mmkvpodhelper.rb b/flutter/tool/mmkvpodhelper.rb index 7a25b828..4b8628c9 100644 --- a/flutter/tool/mmkvpodhelper.rb +++ b/flutter/tool/mmkvpodhelper.rb @@ -18,10 +18,21 @@ # limitations under the License. # +# from ruby 3.2 File.exists is broken, we need compat function +def mmkv_file_exists(file) + is_exist = false + if File.methods.include?(:exists?) + is_exist = File.exists? file + else + is_exist = File.exist? file + end + return is_exist +end + # to avoid conflict of the native lib name 'libMMKV.so' on iOS, we need to change the plugin name 'mmkv' to 'mmkvflutter' def fix_mmkv_plugin_name_inside_dependencies(plugin_deps_file) plugin_deps_file = File.expand_path(plugin_deps_file) - unless File.exists?(plugin_deps_file) + unless mmkv_file_exists(plugin_deps_file) raise "#{plugin_deps_file} must exist. If you're running pod install manually, make sure flutter pub get is executed first.(mmkvpodhelper.rb)" end @@ -41,7 +52,7 @@ def fix_mmkv_plugin_name_inside_dependencies(plugin_deps_file) def fix_mmkv_plugin_name_inside_registrant(plugin_registrant_path, is_module) if is_module plugin_registrant_file = File.expand_path(File.join(plugin_registrant_path, 'FlutterPluginRegistrant.podspec')) - if File.exists?(plugin_registrant_file) + if mmkv_file_exists(plugin_registrant_file) registrant = File.read(plugin_registrant_file) if registrant.sub!("dependency 'mmkv'", "dependency 'mmkvflutter'") File.write(plugin_registrant_file, registrant) @@ -51,7 +62,7 @@ def fix_mmkv_plugin_name_inside_registrant(plugin_registrant_path, is_module) plugin_registrant_source = is_module ? File.expand_path(File.join(plugin_registrant_path, 'Classes', 'GeneratedPluginRegistrant.m')) : File.expand_path(File.join(plugin_registrant_path, 'GeneratedPluginRegistrant.m')) - if File.exists?(plugin_registrant_source) + if mmkv_file_exists(plugin_registrant_source) registrant_source = File.read(plugin_registrant_source) if registrant_source.gsub!(/\bmmkv\b/, 'mmkvflutter') File.write(plugin_registrant_source, registrant_source) diff --git a/iOS/MMKV/MMKV.xcodeproj/project.pbxproj b/iOS/MMKV/MMKV.xcodeproj/project.pbxproj index 6eca7016..835766d5 100644 --- a/iOS/MMKV/MMKV.xcodeproj/project.pbxproj +++ b/iOS/MMKV/MMKV.xcodeproj/project.pbxproj @@ -486,7 +486,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; - MARKETING_VERSION = 1.2.15; + MARKETING_VERSION = 1.2.16; "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-framework", UIKit, @@ -529,7 +529,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; - MARKETING_VERSION = 1.2.15; + MARKETING_VERSION = 1.2.16; "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-framework", UIKit, @@ -728,7 +728,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; - MARKETING_VERSION = 1.2.15; + MARKETING_VERSION = 1.2.16; "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-framework", UIKit, @@ -766,7 +766,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; - MARKETING_VERSION = 1.2.15; + MARKETING_VERSION = 1.2.16; "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-framework", UIKit, @@ -811,7 +811,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; - MARKETING_VERSION = 1.2.15; + MARKETING_VERSION = 1.2.16; "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-framework", UIKit, @@ -858,7 +858,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; - MARKETING_VERSION = 1.2.15; + MARKETING_VERSION = 1.2.16; "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-framework", UIKit,