Skip to content

Instantly share code, notes, and snippets.

@bierbaumtim
Created May 14, 2023 17:15
Show Gist options
  • Save bierbaumtim/63c5057fc2889558d1801d95d93b6c6c to your computer and use it in GitHub Desktop.
Save bierbaumtim/63c5057fc2889558d1801d95d93b6c6c to your computer and use it in GitHub Desktop.
Flutter iOS Keychain Availability Handler
import 'dart:async';
import 'package:flutter/services.dart';
class SecureStorageService {
static const MethodChannel _channel =
MethodChannel('com.example.test/secstore/commands');
static const _eventChannel =
EventChannel('com.example.test/secstore/events');
late Stream<dynamic> _eventsFetch;
Stream<bool> get onNotificationRecieved => _eventsFetch
.where((event) => event is bool)
.map((event) => event as bool);
SecureStorageService() {
_eventsFetch = _eventChannel.receiveBroadcastStream();
}
Future<bool> isProtectedDataAvailable() async {
try {
final result = await _channel.invokeMethod<bool>(
'isProtectedDataAvailable',
);
return result ?? false;
} on PlatformException catch (_) {
return false;
}
}
}
import Flutter
import UIKit
import os.log
public class SecureStorageDelegate: NSObject, FlutterPlugin, FlutterStreamHandler {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "com.example.test/secstore/commands", binaryMessenger: registrar.messenger())
let secStoreEventChannel = FlutterEventChannel(name: "com.example.test/secstore/events", binaryMessenger: registrar.messenger())
let instance = SecureStorageDelegate()
registrar.addMethodCallDelegate(instance, channel: channel)
registrar.addApplicationDelegate(instance)
secStoreEventChannel.setStreamHandler(instance)
}
private var secStoreAvailabilitySink: FlutterEventSink?
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
os_log("handle %@ on SecureStorageDelegate", call.method)
switch call.method {
case "isProtectedDataAvailable":
result(UIApplication.shared.isProtectedDataAvailable)
default:
result(FlutterMethodNotImplemented)
}
}
public func applicationProtectedDataDidBecomeAvailable(_ application: UIApplication) {
guard let sink = secStoreAvailabilitySink else {
os_log("secStoreAvailabilitySink is null", type: OSLogType.error)
return
}
sink(true)
}
public func applicationProtectedDataWillBecomeUnavailable(_ application: UIApplication) {
guard let sink = secStoreAvailabilitySink else {
os_log("secStoreAvailabilitySink is null", type: OSLogType.error)
return
}
sink(false)
}
public func onListen(withArguments arguments: Any?,
eventSink: @escaping FlutterEventSink) -> FlutterError? {
self.secStoreAvailabilitySink = eventSink
os_log("set eventSink")
return nil
}
public func onCancel(withArguments arguments: Any?) -> FlutterError? {
secStoreAvailabilitySink = nil
return nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment