Skip to content

flutter_setup

guoling edited this page Dec 13, 2024 · 29 revisions

license PRs Welcome Release Version Platform

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.

MMKV for Flutter

Features

  • Efficient. MMKV uses mmap to keep memory synced with file, and protobuf to encode/decode values, making the most of the native platform to achieve the best performance.

    • Multi-Process concurrency: MMKV supports concurrent read-read and read-write access between processes.
  • Easy-to-use. You can use MMKV as you go. All changes are saved immediately, no sync, no apply calls needed.

  • Small.

    • A handful of files: MMKV contains process locks, encode/decode helpers and mmap logics, and nothing more. It's really tidy.
    • About 100K in binary size: MMKV adds about 100K per architecture on App size, and much less when zipped (APK/IPA).

Getting Started

Installation

Add the following lines to pubspec.yaml on your app module. Then run flutter pub get.

dependencies:
  mmkv: ">=2.0.1"
  ...

If you already include MMKV native lib in your App, you need to upgrade to a version newer than v2.0.1.

iOS

Starting from v1.3.5, there's no need to change the plugin name 'mmkv' to 'mmkvflutter'. You should remove the script (fix_mmkv_plugin_name()) previously added in your Podfile.

Android

If you previously use com.tencent.mmkv-static or com.tencent.mmkv-shared in your Android App, you should move to com.tencent.mmkv. And if your App depends on any 3rd SDK that embeds com.tencent.mmkv-static or com.tencent.mmkv-shared, you can add this lines to your build.gradle to avoid conflict:

    dependencies {
        ...

        modules {
            module("com.tencent:mmkv-static") {
                replacedBy("com.tencent:mmkv", "Using mmkv for flutter")
            }
            module("com.tencent:mmkv-shared") {
                replacedBy("com.tencent:mmkv", "Using mmkv for flutter")
            }
        }
    }

Setup

You can use MMKV as you go. All changes are saved immediately, no sync, no apply calls needed.
Setup MMKV on App startup, say your main() function, add these lines:

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');

  runApp(MyApp());
}

Note that you have to wait for MMKV to finish initialization before accessing any MMKV instance.

CRUD Operations

  • MMKV has a global instance, that can be used directly:

    import 'package:mmkv/mmkv.dart';
        
    var mmkv = MMKV.defaultMMKV();
    mmkv.encodeBool('bool', true);
    print('bool = ${mmkv.decodeBool('bool')}');
    
    mmkv.encodeInt32('int32', (1<<31) - 1);
    print('max int32 = ${mmkv.decodeInt32('int32')}');
    
    mmkv.encodeInt('int', (1<<63) - 1);
    print('max int = ${mmkv.decodeInt('int')}');
    
    String str = 'Hello Flutter from MMKV';
    mmkv.encodeString('string', str);
    print('string = ${mmkv.decodeString('string')}');
    
    str = 'Hello Flutter from MMKV with bytes';
    var bytes = MMBuffer.fromList(Utf8Encoder().convert(str))!;
    mmkv.encodeBytes('bytes', bytes);
    bytes.destroy();
    
    bytes = mmkv.decodeBytes('bytes')!;
    print('bytes = ${Utf8Decoder().convert(bytes.asList()!)}');
    bytes.destroy();

    As you can see, MMKV is quite easy to use.

    Note: If you come across to failing to load defaultMMKV() on Android after upgrading Flutter from 1.20+ to 2.0+, you can try passing this encryption key '\u{2}U' instead.

    var mmkv = MMKV.defaultMMKV(cryptKey: '\u{2}U');
  • Deleting & Querying:

    var mmkv = MMKV.defaultMMKV();
    
    mmkv.removeValue('bool');
    print('contains "bool": ${mmkv.containsKey('bool')}');
    
    mmkv.removeValues(['int32', 'int']);
    print('all keys: ${mmkv.allKeys}');
  • If different modules/logic need isolated storage, you can also create your own MMKV instance separately:

    var mmkv = MMKV('test');
    mmkv.encodeBool('bool', true);
    print('bool = ${mmkv.decodeBool('bool')}');
  • If multi-process accessing is needed, you can set MMKV.MULTI_PROCESS_MODE on MMKV initialization:

    var mmkv = MMKV('test-multi-process', mode: MMKVMode.MULTI_PROCESS_MODE);
    mmkv.encodeBool('bool', true);
    print('bool = ${mmkv.decodeBool('bool')}');

Supported Types

  • Primitive Types:

    • bool, int, double
  • Classes & Collections:

    • String, List<int>, MMBuffer

Log

  • By default, MMKV prints log to logcat/console, which is not convenient for diagnosing online issues. You can set up MMKV log redirecting on App startup on the native interface of MMKV. Checkout how to do it on Android / iOS. Due to the current limitation of Flutter runtime, we can't redirect the log on the Flutter side.

  • You can turn off MMKV's logging once and for all on initialization (which we strongly disrecommend).
    Note: You should never turn MMKV's log off unless you have very strong evidence that it makes your App slow.

    final rootDir = await MMKV.initialize(logLevel: MMKVLogLevel.None);

Encryption

  • By default MMKV stores all key-values in plain text on file, relying on Android's/iOS's sandbox to make sure the file is encrypted. Should you worry about information leaking, you can choose to encrypt MMKV.

    final encryptKey = 'MyEncryptKey';
    var mmkv = MMKV('test-encryption', cryptKey: encryptKey);
  • You can change the encryption key later as you like. You can also change an existing MMKV instance from encrypted to unencrypted, or vice versa.

    // an unencrypted MMKV instance
    var mmkv = MMKV('test-encryption');
    
    // change from unencrypted to encrypted
    mmkv.reKey('Key_seq_1');
    
    // change encryption key
    mmkv.reKey('Key_seq_2');
    
    // change from encrypted to unencrypted
    kmmkv.reKey(null);

Customize location

  • By default, MMKV stores file inside $(FilesDir)/mmkv/. You can customize MMKV's root directory on App startup:

    final dir = await getApplicationSupportDirectory();
    final rootDir = await MMKV.initialize(dir, rootDir: dir.path + '/mmkv_2');
    print('MMKV for flutter with rootDir = $rootDir');
  • You can even customize any MMKV instance's location:

    final dir = await getApplicationSupportDirectory();
    var mmkv = MMKV('testCustomDir', rootDir: dir.path + '/mmkv_3');

    Note: It's recommended to store MMKV files inside your App's sandbox path. DO NOT store them on external storage(aka SD card). If you have to do it, you should follow Android's scoped storage enforcement.

Backup & Restore

  • You can use MMKV's backup & restore API to backup your data to somewhere else, and restore them later.

    final rootDir = ...;
    final backupRootDir = rootDir + '/mmkv_backup';
    // backup one instance
    var ret = MMKV.backupOneToDirectory(mmapID, backupRootDir);
    // backup all instances
    var count = MMKV.backupAllToDirectory(backupRootDir);
    
    // restore one instance
    ret = MMKV.restoreOneMMKVFromDirectory(mmapID, backupRootDir);
    // restore all instances
    count = MMKV.restoreAllFromDirectory(backupRootDir);

Auto Expiration

  • Starting from v1.3.0, you can upgrade MMKV to auto key expiration. Note that this is a breaking change. Once upgraded to auto key expiration, the file is not valid for any older version of MMKV (<= v1.2.16) to operate correctly.

  • Global Expiration. The most simple way to do it is to turn on auto key expiration for all keys in the whole file.

    // expire in a day
    mmkv.enableAutoKeyExpire(MMKV.ExpireInDay); // MMKV.ExpireInDay = 24 * 60 * 60

    Or, if you prefer, you can enable auto key expiration without setting a global expiration duration. In this case, each key is not expired by default.

    // enable auto key expiration without global duration
    mmkv.enableAutoKeyExpire(MMKV.ExpireNever); // MMKV.ExpireNever = 0
  • Individual Expiration. You can set a special expiration duration for a key, regardless with the file has a global duration or not. Note that you have to enable auto key expiration first.

    // enable auto key expiration with an hour duration
    mmkv.enableAutoKeyExpire(MMKV.ExpireInHour); // MMKV.ExpireInHour = 60 * 60
    
    // set a key with the file's global expiration duration, aka MMKV.ExpireInHour
    mmkv.encodeString('key_1', 'some value');
    
    // set a special key that expires in two hours
    mmkv.encodeString('key_2', 'some value', 2 * 60 * 60);
    
    // set a special key that never expires
    mmkv.encodeString('key_3', 'some value', MMKV.ExpireNever);

    Or, if you prefer, you can enable auto key expiration without setting a global expiration duration. In this case, each key is not expired by default.

    // enable auto key expiration without global duration
    mmkv.enableAutoKeyExpire(MMKV.ExpireNever); // MMKV.ExpireNever = 0
    
    // set a key that never expires
    mmkv.encodeString('key_1', 'some value');
    
    // set a special key that expires in an hour
    mmkv.encodeString('key_2', 'some value', MMKV.ExpireInHour);
  • The expire duration is counted in seconds. MMKV has some pre-defined duration for your convenience. You can use any other duration you prefer. For example, expiration in a week is 7 * 24 * 60 * 60.

    static const int ExpireNever = 0;
    static const int ExpireInMinute = 60;
    static const int ExpireInHour = 60 * 60;
    static const int ExpireInDay = 24 * 60 * 60;
    static const int ExpireInMonth = 30 * 24 * 60 * 60;
    static const int ExpireInYear = 365 * 30 * 24 * 60 * 60;

Change Log

Check out the CHANGELOG.md for details of change history.