Created
May 31, 2022 22:32
-
-
Save electricbolt/e95bb22f735c8a83bdf9fffaa3845997 to your computer and use it in GitHub Desktop.
Example of Flutter FFI extensions for calling Objective-C methods.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ignore_for_file: non_constant_identifier_names | |
| import 'dart:convert'; | |
| import 'dart:ffi'; | |
| import "package:ffi/ffi.dart"; | |
| /// # Get Objective-C singleton. | |
| /// Pointer<Void> instance = objc_msgSend_object(objc_getClass('UIDevice'), 'currentDevice'); | |
| /// | |
| /// # Read String. | |
| /// Pointer<Void> value = objc_msgSend_object(instance, 'localizedModel'); | |
| /// String s = NSStringToDartString(value); | |
| /// | |
| /// # Read int, bool or double. | |
| /// int i = objc_msgSend_int(instance, 'userInterfaceIdiom'); | |
| /// bool b = objc_msgSend_int(instance, 'isMultitaskingSupported') != 0; | |
| /// double d = objc_msgSend_double(instance, 'batteryLevel'); | |
| final DynamicLibrary _library = DynamicLibrary.process(); | |
| /// Objective-C prototype: | |
| /// id objc_getClass(const char *name); | |
| Pointer<Void> Function(Pointer<Utf8>) _objc_getClass = _library | |
| .lookup<NativeFunction<Pointer<Void> Function(Pointer<Utf8>)>>( | |
| 'objc_getClass') | |
| .asFunction(); | |
| Pointer<Void> objc_getClass(String name) { | |
| return _objc_getClass(name.toNativeUtf8()); | |
| } | |
| /// Objective-C prototype: | |
| /// SEL sel_registerName(const char *str); | |
| Pointer<Void> Function(Pointer<Utf8>) _sel_registerName = _library | |
| .lookup<NativeFunction<Pointer<Void> Function(Pointer<Utf8>)>>( | |
| 'sel_registerName') | |
| .asFunction(); | |
| Pointer<Void> sel_registerName(String method) { | |
| return _sel_registerName(method.toNativeUtf8()); | |
| } | |
| /// Objective-C prototype: | |
| /// void objc_msgSend(void) | |
| Pointer<Void> Function(Pointer<Void>, Pointer<Void>) _objc_msgSend_object = | |
| _library | |
| .lookup< | |
| NativeFunction< | |
| Pointer<Void> Function( | |
| Pointer<Void>, Pointer<Void>)>>('objc_msgSend') | |
| .asFunction(); | |
| Pointer<Void> objc_msgSend_object(Pointer<Void> instance, String method) { | |
| Pointer<Void> sel = sel_registerName(method); | |
| return _objc_msgSend_object(instance, sel); | |
| } | |
| /// Objective-C prototype: | |
| /// void objc_msgSend(void) | |
| int Function(Pointer<Void>, Pointer<Void>) _objc_msgSend_int = _library | |
| .lookup<NativeFunction<Int64 Function(Pointer<Void>, Pointer<Void>)>>( | |
| 'objc_msgSend') | |
| .asFunction(); | |
| int objc_msgSend_int(Pointer<Void> instance, String method) { | |
| Pointer<Void> sel = sel_registerName(method); | |
| return _objc_msgSend_int(instance, sel); | |
| } | |
| /// Objective-C prototype: | |
| /// void objc_msgSend(void) | |
| double Function(Pointer<Void>, Pointer<Void>) _objc_msgSend_double = _library | |
| .lookup<NativeFunction<Double Function(Pointer<Void>, Pointer<Void>)>>( | |
| 'objc_msgSend') | |
| .asFunction(); | |
| double objc_msgSend_double(Pointer<Void> instance, String method) { | |
| Pointer<Void> sel = sel_registerName(method); | |
| return _objc_msgSend_double(instance, sel); | |
| } | |
| /// Objective-C prototype: | |
| /// CFIndex CFStringGetLength(CFStringRef theString); | |
| int Function(Pointer<Void>) CFStringGetLength = _library | |
| .lookup<NativeFunction<Int64 Function(Pointer<Void>)>>('CFStringGetLength') | |
| .asFunction(); | |
| final int kCFStringEncodingUTF8 = 0x08000100; | |
| /// Objective-C prototype: | |
| /// Boolean CFStringGetCString(CFStringRef theString, char *buffer, CFIndex bufferSize, CFStringEncoding encoding); | |
| bool Function(Pointer<Void>, Pointer<Uint8>, int, int) CFStringGetCString = | |
| _library | |
| .lookup< | |
| NativeFunction< | |
| Bool Function(Pointer<Void>, Pointer<Uint8>, Int64, | |
| Int32)>>('CFStringGetCString') | |
| .asFunction(); | |
| /// Converts a NSString to a Dart string. If an error occurs '' is returned. | |
| String NSStringToDartString(Pointer<Void> str) { | |
| int length = CFStringGetLength(str); | |
| print('length is $length'); | |
| Pointer<Uint8> buf = calloc<Uint8>(length + 1); | |
| bool ok = CFStringGetCString( | |
| str, buf, length + 1, kCFStringEncodingUTF8); | |
| if (ok == false) return ''; | |
| String result = Utf8Decoder().convert(buf.asTypedList(length)); | |
| calloc.free(buf); | |
| return result; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment