Cómo get la class del package

Siguiendo la explicación aquí:

https://github.com/nst/iOS-Runtime-Headers

Estoy intentando get la class del TUPhoneLogger en el package TelephonyUtilities.framework. Sin embargo, el depurador siempre muestra "error: class desconocida" .

Tengo 2 methods diferentes:

Primer método:

NSBundle* b = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/TelephonyUtilities.framework"]; BOOL success = [b load]; NSLog(@"%@", [b definedClasses_dd]); 

Nota: he creado una extensión @interface NSBundle (DDAdditions):

 - (NSArray *)definedClasses_dd { NSMutableArray *array = [NSMutableArray array]; int numberOfClasses = objc_getClassList(NULL, 0); Class *classes = calloc(sizeof(Class), numberOfClasses); numberOfClasses = objc_getClassList(classes, numberOfClasses); for (int i = 0; i < numberOfClasses; ++i) { Class c = classes[i]; if ([NSBundle bundleForClass:c] == self) { [array addObject:c]; const char* nameOfClass = class_getName(c); NSString* classString = [NSString stringWithUTF8String:nameOfClass]; if([classString isEqualToString:@"TUPhoneLogger"]) { NSLog(@"Found it! TUPhoneLogger"); id test= [[c alloc] init]; NSLog(@"test: %@", test); } } } free(classes); 

Segundo método:

 NSBundle* b = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/TelephonyUtilities.framework"]; Class telephonyClass = [b classNamed:@"TUPhoneLogger"]; id test= [[telephonyClass alloc] init]; NSLog(@"%@", test); 

En el depurador:

introduzca la descripción de la imagen aquí

Hay un tercer método (que prefiero)

a) Usted vincula a este marco estáticamente (es decir, lo agrega a su objective)

b) Usted define la class necesaria (TUPhoneLogger) en la class .h. Puede getla utilizando class-dump (-z)

c) Incluye este file .h

d) Solo usa class privada de la misma manera que usa class pública.

Pequeña explicación adicional

No hay "magia" sobre los frameworks privados y la API privada. Lo único diferente es que no están documentados e incluidos en files .h.

Los pasos b) yc) crean classs .h con ellos y, como resultado, pueden usarse exactamente de la misma manera que la API pública habitual.

+1 a Victor, ya que creo que es más simple include el Framework como una biblioteca Build Phase en su proyecto. Los frameworks privados se encuentran en el subdirectory SDK de PrivateFrameworks , pero, de lo contrario, funciona de manera similar a los frameworks públicos (con las diferencias descritas en la respuesta de Victor).

Solo ofreceré otra técnica que funcione, si quieres una carga dinámica :

 #include <dlfcn.h> #import <objc/runtime.h> 

y entonces

 void* handle = dlopen("/System/Library/PrivateFrameworks/TelephonyUtilities.framework/TelephonyUtilities", RTLD_NOW); Class c = NSClassFromString(@"TUPhoneLogger"); id instance = [[c alloc] init]; dlclose(handle); 

Supongo que una ventaja de dlopen() es que no tiene que recordar llamar a load , lo que lo llevó a su segundo ejemplo. Una desventaja es que deberías llamar a dlclose() luego.

Nota: la ligera diferencia en la ruta para dlopen() vs NSBundle bundleWithPath: (file vs. dir)

Nota ++: este código no funcionará en el simulador, ya que es probable que el simulador no tenga ese marco (no hay una funcionalidad real del teléfono)


Actualizar

En iOS 9.3, Apple eliminó Frameworks privados del SDK. Entonces, desde entonces, en general, es el caso que necesitará utilizar esta técnica dinámica, si Framework no es uno de los frameworks públicos de iOS. Mira esta respuesta para más