def swizzled(self, sel, *args): print('{}:{} called'.format(time.ctime(), method)) print(args) argtypes = parse_types( ObjCInstanceMethod(ObjCInstance(self), method).encoding)[1][2:] newargs = [] for a, ty in zip(args, argtypes): if a is not None and ty is c_void_p: def p(): print(ObjCInstance(a)) ui.delay(p, 1) newargs.append(a) else: def p(): print(a) ui.delay(p, 1) newargs.append(a) returnval = ObjCInstanceMethod(ObjCInstance(self), 'original' + method)(*newargs) print('returnval', returnval) if isinstance(returnval, ObjCInstance): return returnval.ptr else: return returnval
def swizzle(cls, old_sel, new_fcn): '''swizzles cls.old_sel with new_fcn. Assumes encoding is the same. if class already has swizzledSelector, unswizzle first. original selector can be called via originalSelectir ''' orig_method=c.class_getInstanceMethod(cls.ptr, sel(old_sel)) #new_method=c.class_getInstanceMethod(cls, sel(new_sel)) type_encoding=str(cls.instanceMethodSignatureForSelector_(sel(old_sel))._typeString()) parsed_types = parse_types(str(type_encoding)) restype = parsed_types[0] argtypes = parsed_types[1] # Check if the number of arguments derived from the selector matches the actual function: argspec = inspect.getargspec(new_fcn) if len(argspec.args) != len(argtypes): raise ValueError('%s has %i arguments (expected %i)' % (method, len(argspec.args), len(argtypes))) IMPTYPE = ctypes.CFUNCTYPE(restype, *argtypes) imp = IMPTYPE(new_fcn) retain_global(imp) new_sel='_original'+old_sel didAdd=c.class_addMethod(cls.ptr, sel(new_sel), imp, type_encoding) new_method=c.class_getInstanceMethod(cls.ptr, sel(new_sel)) # swap imps c.method_exchangeImplementations.restype=None c.method_exchangeImplementations.argtypes=[c_void_p,c_void_p] c.method_exchangeImplementations(orig_method, new_method) return new_sel
def swizzle(cls_name, selector_name, fn): cls = ObjCClass(cls_name).ptr new_selector_name = SWIZZLED_SELECTOR_PREFIX + selector_name new_selector = sel(new_selector_name) if c.class_getInstanceMethod(cls, new_selector): error('Skipping swizzling, already responds to {} selector'.format( new_selector_name)) return selector = sel(selector_name) method = c.class_getInstanceMethod(cls, selector) if not method: error('Failed to get {} instance method'.format(selector_name)) return type_encoding = c.method_getTypeEncoding(method) parsed_types = parse_types(type_encoding) restype = parsed_types[0] argtypes = parsed_types[1] IMPTYPE = CFUNCTYPE(restype, *argtypes) imp = IMPTYPE(fn) retain_global(imp) did_add = c.class_addMethod(cls, new_selector, imp, type_encoding) if not did_add: error('Failed to add {} method'.format(new_selector_name)) return new_method = c.class_getInstanceMethod(cls, new_selector) method_exchangeImplementations(method, new_method)
def add_method(cls_name, selector_name, fn, type_encoding): cls = ObjCClass(cls_name).ptr selector = sel(selector_name) if c.class_getInstanceMethod(cls, selector): error( 'Failed to add method, class {} already provides method {}'.format( cls_name, selector_name)) return parsed_types = parse_types(type_encoding) restype = parsed_types[0] argtypes = parsed_types[1] IMPTYPE = CFUNCTYPE(restype, *argtypes) imp = IMPTYPE(fn) retain_global(imp) did_add = c.class_addMethod(cls, selector, imp, c_char_p(type_encoding.encode('utf-8'))) if not did_add: error('Failed to add class method') return did_add
def swizzle(cls, selector, new_fcn,type_encoding=None): '''swizzles ObjCClass cls's selector with implementation from python new_fcn. new_fcn needs to adjere to ther type encoding of the original, including the two "hidden" arguments _self, _sel. if a class is already swizzled, this will override swizzled implemetation, and use new method. We could implement a forwarding system, but it becomes hard to unswizzle because there is no way to remove a selector once added. A method can always get its predecessor by simply prepending original to its selector name. If the referenced method does not exist, must supply type_encoding. ''' if not type_encoding: type_encoding=_str_to_bytes(str(cls.instanceMethodSignatureForSelector_(sel(selector))._typeString())) else: type_encoding=_str_to_bytes(type_encoding) parsed_types = parse_types(_str_to_bytes(type_encoding)) restype = parsed_types[0] argtypes = parsed_types[1] # Check if the number of arguments derived from the selector matches the actual function: try: argspec=inspect.getargspec(new_fcn.__closure__[0].cell_contents) except: argspec = inspect.getargspec(new_fcn) if len(argspec.args) != len(argtypes): raise ValueError('%s has %i arguments (expected %i)' % (new_fcn, len(argspec.args), len(argtypes))) IMPTYPE = ctypes.CFUNCTYPE(restype, *argtypes) imp = IMPTYPE(new_fcn) retain_global(imp) #find rootmost parent # add new to orig_.... N (N-3) (N-2) (N-1) # then starting at end, swap up the chain if not c.class_getInstanceMethod(cls.ptr, sel(selector)): # just add the selector new_sel = selector didAdd=c.class_addMethod(cls.ptr, sel(new_sel), imp, (type_encoding)) return new_sel = 'original'+selector didAdd=c.class_addMethod(cls.ptr, sel(new_sel), imp, (type_encoding)) method_exchangeImplementations=c.method_exchangeImplementations method_exchangeImplementations.restype=None method_exchangeImplementations.argtypes=[c_void_p,c_void_p] method_setImplementation=c.method_setImplementation method_setImplementation.restype=None method_setImplementation.argtypes=[c_void_p, c_void_p] if didAdd: orig_method=c.class_getInstanceMethod(cls.ptr, sel(selector)) new_method=c.class_getInstanceMethod(cls.ptr, sel(new_sel)) method_exchangeImplementations(orig_method, new_method) else: # setimp, orig_method=c.class_getInstanceMethod(cls.ptr, sel(selector)) method_setImplementation(orig_method,imp)
def swizzled(self, sel, *args): with Lock(): logger.debug('# # # # # {} # # # # #'.format(method)) logger.debug(' self:{}'.format(self)) logger.debug(' args:{}'.format(args)) argtypes = parse_types( ObjCInstanceMethod(ObjCInstance(self), method).encoding)[1][2:] newargs = [] argidx = 0 for a, ty in zip(args, argtypes): argidx += 1 if a is not None and ty is c_void_p: logger.debug(' {}\n {}\n {}'.format( argidx, ObjCInstance(a), ty)) newargs.append(ObjCInstance(a)) elif a is not None and ty is ObjCBlock: def block_logger(_cmd, requestid, matches): logger.debug( '__logger_block: call to {}({}). args: {}, {}'. format(ObjCInstance(a), _cmd, requestid, matches)) #logger.debug('{}'.format(signature)) #invoke=cast(bb.ptr,POINTER(block_literal)).contents.invoke #invoke(_cmd, requestid, matches) blk = ObjCBlock(block_logger, restype=None, argtypes=[c_void_p, c_int, c_void_p]) newargs.append(blk) else: logger.debug(' {}\n {}\n {}'.format( argidx, (a), ty)) #ui.delay(p,1) newargs.append(a) selfinstance = ObjCInstance(self) logger.debug(('self=', selfinstance)) try: originalmethod = ObjCInstanceMethod(ObjCInstance(self), 'original' + method) #logger.debug(originalmethod) except AttributeError: import console console.hud_alert(method) logger.debug(' attrib error, returning none') return None if originalmethod: logger.debug((' newargs', newargs)) returnval = originalmethod(*newargs) logger.debug((' =====>', returnval)) if isinstance(returnval, ObjCInstance): return returnval.ptr else: return returnval
def _add_method(cls, func): # void, object, selector type_encoding = "v@:" sel_name = str(uuid.uuid4()) sel = objc_util.sel(sel_name) class_ptr = objc_util.object_getClass(cls.ptr) # ----------------- Modified from objc_util.add_method ------------------ # parsed_types = objc_util.parse_types(type_encoding) restype, argtypes, _ = parsed_types imp = ctypes.CFUNCTYPE(restype, *argtypes)(func) objc_util.retain_global(imp) if isinstance(type_encoding, str): type_encoding = type_encoding.encode('ascii') objc_util.class_addMethod(class_ptr, sel, imp, type_encoding) # ----------------------------------------------------------------------- # return sel
def swizzle(cls, selector, new_fcn): '''swizzles ObjCClass cls's selector with implementation from python new_fcn. new_fcn needs to adhere to the type encoding of the original, including the two "hidden" arguments _self, _sel. if a class is already swizzled, this will override swizzled implementation, and use new method. We could implement a forwarding system, but it becomes hard to unswizzle because there is no way to remove a selector once added. A method can always get its predecessor by simply prepending original to its selector name. ''' type_encoding = str( cls.instanceMethodSignatureForSelector_(sel(selector))._typeString()) parsed_types = parse_types(str(type_encoding)) restype = parsed_types[0] argtypes = parsed_types[1] # Check if the number of arguments derived from the selector matches the actual function: argspec = inspect.getargspec(new_fcn) if len(argspec.args) != len(argtypes): raise ValueError('%s has %i arguments (expected %i)' % (method, len(argspec.args), len(argtypes))) IMPTYPE = ctypes.CFUNCTYPE(restype, *argtypes) imp = IMPTYPE(new_fcn) retain_global(imp) #find rootmost parent # add new to orig_.... N (N-3) (N-2) (N-1) # then starting at end, swap up the chain if not c.class_getInstanceMethod(cls.ptr, sel(selector)): return new_sel = 'original' + selector didAdd = c.class_addMethod(cls.ptr, sel(new_sel), imp, type_encoding) method_exchangeImplementations = c.method_exchangeImplementations method_exchangeImplementations.restype = None method_exchangeImplementations.argtypes = [c_void_p, c_void_p] method_setImplementation = c.method_setImplementation method_setImplementation.restype = None method_setImplementation.argtypes = [c_void_p, c_void_p] if didAdd: orig_method = c.class_getInstanceMethod(cls.ptr, sel(selector)) new_method = c.class_getInstanceMethod(cls.ptr, sel(new_sel)) method_exchangeImplementations(orig_method, new_method) else: # setimp, orig_method = c.class_getInstanceMethod(cls.ptr, sel(selector)) method_setImplementation(orig_method, imp)
def add_method(method, cls): guard_objc_util() import ctypes import objc_util import uuid encoding = "v@:" # this code is borrowed from `objc_util._add_method` parsed_types = objc_util.parse_types(encoding) restype = parsed_types[0] argtypes = parsed_types[1] IMPTYPE = ctypes.CFUNCTYPE(restype, *argtypes) imp = IMPTYPE(method) objc_util.retain_global(imp) selector = objc_util.sel(str(uuid.uuid1()).replace("-", "")) objc_util.class_addMethod(objc_util.object_getClass(cls.ptr), selector, imp, encoding.encode("ascii")) return selector
def swizzled(self,sel,*args): print('{}:{} called'.format(time.ctime(),method)) print (args) argtypes=parse_types(ObjCInstanceMethod(ObjCInstance(self), method).encoding)[1][2:] newargs=[] for a,ty in zip(args,argtypes): if a is not None and ty is c_void_p: def p(): print (ObjCInstance(a)) ui.delay(p,1) newargs.append(a) else: def p(): print(a) ui.delay(p,1) newargs.append(a) returnval= ObjCInstanceMethod(ObjCInstance(self), 'original'+method)(*newargs) print('returnval',returnval) if isinstance(returnval,ObjCInstance): return returnval.ptr else: return returnval
def swizzle(cls, selector, new_fcn, type_encoding=None, debug=False): '''swizzles ObjCClass cls's selector with implementation from python new_fcn. new_fcn needs to adjere to ther type encoding of the original, including the two "hidden" arguments _self, _sel. if a class is already swizzled, this will override swizzled implemetation, and use new method. We could implement a forwarding system, but it becomes hard to unswizzle because there is no way to remove a selector once added. A method can always get its predecessor by simply prepending original to its selector name. If the referenced method does not exist, must supply type_encoding. ''' if not type_encoding: type_encoding = _str_to_bytes( str( cls.instanceMethodSignatureForSelector_( sel(selector))._typeString())) else: type_encoding = _str_to_bytes(type_encoding) parsed_types = parse_types(_str_to_bytes(type_encoding)) restype = parsed_types[0] argtypes = parsed_types[1] # Check if the number of arguments derived from the selector matches the actual function: try: argspec = inspect.getargspec(new_fcn.__closure__[0].cell_contents) except: argspec = inspect.getargspec(new_fcn) has_varargs = inspect.getargspec(new_fcn).varargs if (len(argspec.args) != len(argtypes)) and not has_varargs: raise ValueError('%s has %i arguments (expected %i)' % (new_fcn, len(argspec.args), len(argtypes))) for i, arg in enumerate(argtypes): if arg == ObjCBlock: if debug: print('replace block with voidp') argtypes[i] = ctypes.c_void_p IMPTYPE = ctypes.CFUNCTYPE(restype, *argtypes) imp = IMPTYPE(new_fcn) retain_global(imp) if debug: print(restype) print(argtypes) print(selector) print(cls) #find rootmost parent # add new to orig_.... N (N-3) (N-2) (N-1) # then starting at end, swap up the chain if not c.class_getInstanceMethod(cls.ptr, sel(selector)): # just add the selector new_sel = selector didAdd = c.class_addMethod(cls.ptr, sel(new_sel), imp, (type_encoding)) return new_sel = 'original' + selector didAdd = c.class_addMethod(cls.ptr, sel(new_sel), imp, (type_encoding)) method_exchangeImplementations = c.method_exchangeImplementations method_exchangeImplementations.restype = None method_exchangeImplementations.argtypes = [c_void_p, c_void_p] method_setImplementation = c.method_setImplementation method_setImplementation.restype = None method_setImplementation.argtypes = [c_void_p, c_void_p] if didAdd: orig_method = c.class_getInstanceMethod(cls.ptr, sel(selector)) new_method = c.class_getInstanceMethod(cls.ptr, sel(new_sel)) method_exchangeImplementations(orig_method, new_method) else: # setimp, orig_method = c.class_getInstanceMethod(cls.ptr, sel(selector)) method_setImplementation(orig_method, imp)