| import sys | |
| try: | |
| from ctypes import cdll, c_void_p, c_char_p, util | |
| except ImportError: | |
| # ctypes is an optional module. If it's not present, we're limited in what | |
| # we can tell about the system, but we don't want to prevent the module | |
| # from working. | |
| print("ctypes isn't available; iOS system calls will not be available", file=sys.stderr) | |
| objc = None | |
| else: | |
| # ctypes is available. Load the ObjC library, and wrap the objc_getClass, | |
| # sel_registerName methods | |
| # find_library() resolves a system library through the dyld shared cache, | |
| # which needs _dyld_shared_cache_contains_path(); that is unavailable before | |
| # iOS 14, so fall back to the bare name, which dyld resolves by itself. | |
| lib = util.find_library("objc") or "libobjc.dylib" | |
| try: | |
| objc = cdll.LoadLibrary(lib) | |
| except OSError: | |
| raise ImportError("ObjC runtime library couldn't be loaded") | |
| objc.objc_getClass.restype = c_void_p | |
| objc.objc_getClass.argtypes = [c_char_p] | |
| objc.sel_registerName.restype = c_void_p | |
| objc.sel_registerName.argtypes = [c_char_p] | |
| def get_platform_ios(): | |
| # Determine if this is a simulator using the multiarch value | |
| is_simulator = sys.implementation._multiarch.endswith("simulator") | |
| # We can't use ctypes; abort | |
| if not objc: | |
| return None | |
| # Most of the methods return ObjC objects | |
| objc.objc_msgSend.restype = c_void_p | |
| # All the methods used have no arguments. | |
| objc.objc_msgSend.argtypes = [c_void_p, c_void_p] | |
| # Equivalent of: | |
| # device = [UIDevice currentDevice] | |
| UIDevice = objc.objc_getClass(b"UIDevice") | |
| SEL_currentDevice = objc.sel_registerName(b"currentDevice") | |
| device = objc.objc_msgSend(UIDevice, SEL_currentDevice) | |
| # Equivalent of: | |
| # device_systemVersion = [device systemVersion] | |
| SEL_systemVersion = objc.sel_registerName(b"systemVersion") | |
| device_systemVersion = objc.objc_msgSend(device, SEL_systemVersion) | |
| # Equivalent of: | |
| # device_systemName = [device systemName] | |
| SEL_systemName = objc.sel_registerName(b"systemName") | |
| device_systemName = objc.objc_msgSend(device, SEL_systemName) | |
| # Equivalent of: | |
| # device_model = [device model] | |
| SEL_model = objc.sel_registerName(b"model") | |
| device_model = objc.objc_msgSend(device, SEL_model) | |
| # UTF8String returns a const char*; | |
| SEL_UTF8String = objc.sel_registerName(b"UTF8String") | |
| objc.objc_msgSend.restype = c_char_p | |
| # Equivalent of: | |
| # system = [device_systemName UTF8String] | |
| # release = [device_systemVersion UTF8String] | |
| # model = [device_model UTF8String] | |
| system = objc.objc_msgSend(device_systemName, SEL_UTF8String).decode() | |
| release = objc.objc_msgSend(device_systemVersion, SEL_UTF8String).decode() | |
| model = objc.objc_msgSend(device_model, SEL_UTF8String).decode() | |
| return system, release, model, is_simulator |