如何在 iOS 中使用 NSKeyedArchiver 将已写入文件系统的文件读取为 Flutter 中的字符串?

How to read file as String in Flutter that has been written to filesystem using NSKeyedArchiver in iOS?

更新 iOS 本机应用程序并在 Flutter 上编写应用程序后,我想从 [=] 上的文件系统读取文件=28=]iOS 设备使用 Dart。我要读取的文件之前已使用此 ObjectiveC 代码写入文件系统:

- (void)setAccount:(FTAccountModel *)account {
    _account = account;
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    path = [path stringByAppendingPathComponent:AccountModelPath];
    if (account) {
        NSArray * array = @[account];
        [array writeToFile:path atomically:YES];
        [NSKeyedArchiver archiveRootObject:array toFile:path];
    }
}

我在 Flutter 中使用 path_provider 包尝试了以下方法:

final appDocDir = await getApplicationDocumentsDirectory();
final accountDataFile = File('${appDocDir.path}/$_iosAccountDataFile');
String contents = await accountDataFile.readAsString();
print("contents: $contents");

但是调用readAsString()方法时出现错误:

FileSystemException: Failed to decode data using encoding 'utf-8', path = '/var/mobile/Containers/Data/Application/FBCB4862-E5EA-4C93-8C2E-3DF1F00A8645/Documents/AccountModel.data'

如何使用 DartFlutter 读取 iOS 设备上使用 NSKeyedArchiver 写入的文件?

在撰写此答案时,没有用于读取文件的插件,该文件之前已使用 iOS 中的 NSKeyedArchiver 写入文件系统。读取文件的方式是write custom platform-specific code.

因此 Swift 上的 iOS 平台代码将类似于以下内容:

private func callGetUserIdFromNativeApp(result: @escaping FlutterResult) {
    var account: FTAccountModel?
    let fm = FileManager.default
    let urls = fm.urls(for: .documentDirectory, in: .userDomainMask)
    if (!urls.isEmpty) {
        let file = urls[0].appendingPathComponent("Accounts.data", isDirectory: false)
        
        if (fm.fileExists(atPath: file.path)) {
            if let accountArray: [FTAccountModel] = NSKeyedUnarchiver.unarchiveObject(withFile: file.path) as? [FTAccountModel] {
        
                if (!accountArray.isEmpty) {
                    account = accountArray[0]
                }
            }
        }
    }
    
    if let userId: Int = account?.userId {
        result(String(userId))
    } else {
        result(nil)
    }
}

而flutter部分将使用MethodChannel调用原生代码:

static const MethodChannel _channel = const MethodChannel("CHANNEL_NAME");

static Future<String> getUserIdFromNativeIos() async {
  try {
    return await _channel.invokeMethod("METHOD_NAME");
  } catch (e){
    return _failedString();
  }
}