cómo determinar qué aplicaciones son de fondo y qué aplicación está en primer plano en iOS por ID de la aplicación

Utilizando el método descrito en esta pregunta , puedo obtener una lista de las aplicaciones que se ejecutan en un dispositivo iOS. Conozco los PID y tengo acceso a sus estructuras kinfo_proc . ¿Cómo puedo determinar cuáles son los procesos en primer plano y cuáles son los antecedentes (suponiendo que mi aplicación sea de fondo)?

Traté de encontrar esta base en la información en kinfo_proc (ver 1er enlace), vía kp_proc.p_priority , pero parece que no es posible inferir el estado de fondo / primer plano de la prioridad.

Realmente no me importa si esto funciona correctamente para AppStore Review, pero preferiría un método que funcione sin jailbreak (es decir, las API privadas están bien, pero ¿cuáles?). Quiero que esto funcione al menos en iOS 5

Consideré escribir una extensión de MobileSubstrate simple, inyectándola en todas las aplicaciones y simplemente enganchar la applicationDidBecomeActive de todos MobileSubstrate , pero esto requiere un jailbreak y es demasiado invasivo.

Bueno, parece que algún uso de nm e IDA en el binario SpringBoardServices del simulador me ayudó en esto. El siguiente código funciona en iOS 5.0.1 corriendo en iPod Touch 4, iPhone 4 y iPad1 WiFi (todos no JB) Por supuesto, nunca debes tratar de enviar eso a AppStore

 - (NSArray*) getActiveApps { mach_port_t *p; void *uikit = dlopen(UIKITPATH, RTLD_LAZY); int (*SBSSpringBoardServerPort)() = dlsym(uikit, "SBSSpringBoardServerPort"); p = (mach_port_t *)SBSSpringBoardServerPort(); dlclose(uikit); void *sbserv = dlopen(SBSERVPATH, RTLD_LAZY); NSArray* (*SBSCopyApplicationDisplayIdentifiers)(mach_port_t* port, BOOL runningApps,BOOL debuggable) = dlsym(sbserv, "SBSCopyApplicationDisplayIdentifiers"); //SBDisplayIdentifierForPID - protype assumed,verification of params done void* (*SBDisplayIdentifierForPID)(mach_port_t* port, int pid,char * result) = dlsym(sbserv, "SBDisplayIdentifierForPID"); //SBFrontmostApplicationDisplayIdentifier - prototype assumed,verification of params done,don't call this TOO often(every second on iPod touch 4G is 'too often,every 5 seconds is not) void* (*SBFrontmostApplicationDisplayIdentifier)(mach_port_t* port,char * result) = dlsym(sbserv, "SBFrontmostApplicationDisplayIdentifier"); //Get frontmost application char frontmostAppS[256]; memset(frontmostAppS,sizeof(frontmostAppS),0); SBFrontmostApplicationDisplayIdentifier(p,frontmostAppS); NSString * frontmostApp=[NSString stringWithFormat:@"%s",frontmostAppS]; //NSLog(@"Frontmost app is %@",frontmostApp); //get list of running apps from SpringBoard NSArray *allApplications = SBSCopyApplicationDisplayIdentifiers(p,NO, NO); //Really returns ACTIVE applications(from multitasking bar) /* NSLog(@"Active applications:"); for(NSString *identifier in allApplications) { // NSString * locName=SBSCopyLocalizedApplicationNameForDisplayIdentifier(p,identifier); NSLog(@"Active Application:%@",identifier); } */ //get list of all apps from kernel int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; size_t miblen = 4; size_t size; int st = sysctl(mib, miblen, NULL, &size, NULL, 0); struct kinfo_proc * process = NULL; struct kinfo_proc * newprocess = NULL; do { size += size / 10; newprocess = realloc(process, size); if (!newprocess){ if (process){ free(process); } return nil; } process = newprocess; st = sysctl(mib, miblen, process, &size, NULL, 0); } while (st == -1 && errno == ENOMEM); if (st == 0){ if (size % sizeof(struct kinfo_proc) == 0){ int nprocess = size / sizeof(struct kinfo_proc); if (nprocess){ NSMutableArray * array = [[NSMutableArray alloc] init]; for (int i = nprocess - 1; i >= 0; i--){ int ruid=process[i].kp_eproc.e_pcred.p_ruid; int uid=process[i].kp_eproc.e_ucred.cr_uid; //short int nice=process[i].kp_proc.p_nice; //short int u_prio=process[i].kp_proc.p_usrpri; short int prio=process[i].kp_proc.p_priority; NSString * processID = [[NSString alloc] initWithFormat:@"%d", process[i].kp_proc.p_pid]; NSString * processName = [[NSString alloc] initWithFormat:@"%s", process[i].kp_proc.p_comm]; BOOL systemProcess=YES; if (ruid==501) systemProcess=NO; char * appid[256]; memset(appid,sizeof(appid),0); int intID,intID2; intID=process[i].kp_proc.p_pid,appid; SBDisplayIdentifierForPID(p,intID,appid);/ NSString * appId=[NSString stringWithFormat:@"%s",appid]; if (systemProcess==NO) { if ([appId isEqualToString:@""]) { //final check.if no appid this is not springboard app NSLog(@"(potentially system)Found process with PID:%@ name %@,isSystem:%d,Priority:%d",processID,processName,systemProcess,prio); } else { BOOL isFrontmost=NO; if ([frontmostApp isEqualToString:appId]) { isFrontmost=YES; } NSNumber *isFrontmostN=[NSNumber numberWithBool:isFrontmost]; NSDictionary * dict = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:processID, processName,appId,isFrontmostN, nil] forKeys:[NSArray arrayWithObjects:@"ProcessID", @"ProcessName",@"AppID",@"isFrontmost", nil]]; NSLog(@"PID:%@, name: %@, AppID:%@,isFrontmost:%d",processID,processName,appId,isFrontmost); [array addObject:dict]; } } } free(process); return array; } } } dlclose(sbserv); } 

Por supuesto, el segundo ciclo no es estrictamente necesario, pero también necesitaba nombres y PID no localizados.

¡Gran respuesta! Pero hay un pequeño error tipográfico en tu código, debería ser:

Primero asegúrese de que se define SBSERVPATH y se incluyen los archivos de encabezado correctos:

 #import  #import  #define SBSERVPATH "/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices" 

Luego primero encuentre el puerto SB correcto:

 mach_port_t *port; void *lib = dlopen(SBSERVPATH, RTLD_LAZY); int (*SBSSpringBoardServerPort)() = dlsym(lib, "SBSSpringBoardServerPort"); port = (mach_port_t *)SBSSpringBoardServerPort(); dlclose(lib); 

Y luego encuentra la aplicación activa:

 mach_port_t * port = [self getSpringBoardPort]; // open springboard lib void *lib = dlopen(SBSERVPATH, RTLD_LAZY); // retrieve function SBFrontmostApplicationDisplayIdentifier void *(*SBFrontmostApplicationDisplayIdentifier)(mach_port_t *port, char *result) = dlsym(lib, "SBFrontmostApplicationDisplayIdentifier"); // reserve memory for name char appId[256]; memset(appId, 0, sizeof(appId)); // retrieve front app name SBFrontmostApplicationDisplayIdentifier(port, appId); // close dynlib dlclose(lib); 

Esto es lo que funciona para mí en todos los dispositivos IOS:

 #define UIKITPATH "/System/Library/Framework/UIKit.framework/UIKit" #define SBSERVPATH "/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices" - (NSArray*) getActiveApps { mach_port_t *p; void *uikit = dlopen(UIKITPATH, RTLD_LAZY); int (*SBSSpringBoardServerPort)() = dlsym(uikit, "SBSSpringBoardServerPort"); p = (mach_port_t *)SBSSpringBoardServerPort(); dlclose(uikit); if(self.frameWorkPath == nil || self.frameWorkPath.length == 0) { self.frameWorkPath = @SBSERVPATH; self.frameWorkPath = [self.frameWorkPath stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; } const char *cString = [self.frameWorkPath cStringUsingEncoding:NSUTF8StringEncoding]; //const char *bar = [self.frameWorkPath UTF8String]; void *sbserv = dlopen(cString, RTLD_LAZY); NSArray* (*SBSCopyApplicationDisplayIdentifiers)(mach_port_t* port, BOOL runningApps,BOOL debuggable) = dlsym(sbserv, "SBSCopyApplicationDisplayIdentifiers"); //SBDisplayIdentifierForPID - protype assumed,verification of params done void* (*SBDisplayIdentifierForPID)(mach_port_t* port, int pid,char * result) = dlsym(sbserv, "SBDisplayIdentifierForPID"); //SBFrontmostApplicationDisplayIdentifier - prototype assumed,verification of params done,don't call this TOO often(every second on iPod touch 4G is 'too often,every 5 seconds is not) void* (*SBFrontmostApplicationDisplayIdentifier)(mach_port_t* port,char * result) = dlsym(sbserv, "SBFrontmostApplicationDisplayIdentifier"); //Get frontmost application char frontmostAppS[512]; memset(frontmostAppS,sizeof(frontmostAppS),0); SBFrontmostApplicationDisplayIdentifier(p,frontmostAppS); NSString * frontmostApp=[NSString stringWithFormat:@"%s",frontmostAppS]; if([self iOsMajorVersion] >= 7){ NSNumber *topmost = [NSNumber numberWithBool:YES]; NSMutableDictionary * dict = [[NSMutableDictionary alloc] init]; NSMutableArray * splitted = [frontmostApp componentsSeparatedByString:@"."]; if(frontmostApp.length > 0 && splitted != nil && splitted.count > 1 && topmost.boolValue == YES){ NSString *appname = [splitted lastObject]; [dict setObject:[appname capitalizedString] forKey:@"ProcessName"]; [dict setObject:frontmostApp forKey:@"ProcessID"]; [dict setObject:frontmostApp forKey:@"AppID"]; [dict setObject:topmost forKey:@"isFrontmost"]; NSLog(@"Running TOPMOST App %@",dict); return @[dict]; } else{ return nil; } } //NSLog(@"Frontmost app is %@",frontmostApp); //get list of running apps from SpringBoard NSArray *allApplications = SBSCopyApplicationDisplayIdentifiers(p,NO, NO); //Really returns ACTIVE applications(from multitasking bar) NSLog(@"Active applications:"); for(NSString *identifier in allApplications) { // NSString * locName=SBSCopyLocalizedApplicationNameForDisplayIdentifier(p,identifier); NSLog(@"Active Application:%@",identifier); } //get list of all apps from kernel int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; size_t miblen = 4; size_t size; int st = sysctl(mib, miblen, NULL, &size, NULL, 0); struct kinfo_proc * process = NULL; struct kinfo_proc * newprocess = NULL; do { size += size / 10; newprocess = realloc(process, size); if (!newprocess){ if (process){ free(process); } return nil; } process = newprocess; st = sysctl(mib, miblen, process, &size, NULL, 0); } while (st == -1 && errno == ENOMEM); if (st == 0){ if (size % sizeof(struct kinfo_proc) == 0){ int nprocess = size / sizeof(struct kinfo_proc); if (nprocess){ NSMutableArray * array = [[NSMutableArray alloc] init]; for (int i = nprocess - 1; i >= 0; i--){ int ruid=process[i].kp_eproc.e_pcred.p_ruid; int uid=process[i].kp_eproc.e_ucred.cr_uid; //short int nice=process[i].kp_proc.p_nice; //short int u_prio=process[i].kp_proc.p_usrpri; short int prio=process[i].kp_proc.p_priority; NSString * processID = [[NSString alloc] initWithFormat:@"%d", process[i].kp_proc.p_pid]; NSString * processName = [[NSString alloc] initWithFormat:@"%s", process[i].kp_proc.p_comm]; BOOL systemProcess=YES; if (ruid==501){ systemProcess=NO; } char * appid[256]; memset(appid,sizeof(appid),0); int intID,intID2; intID=process[i].kp_proc.p_pid,appid; SBDisplayIdentifierForPID(p,intID,appid); NSString * appId=[NSString stringWithFormat:@"%s",appid]; if (systemProcess==NO) { if ([appId isEqualToString:@""]) { //final check.if no appid this is not springboard app //NSLog(@"(potentially system)Found process with PID:%@ name %@,isSystem:%d,Priority:%d",processID,processName,systemProcess,prio); } else { BOOL isFrontmost=NO; if ([frontmostApp isEqualToString:appId]) { isFrontmost=YES; } NSNumber *isFrontmostN=[NSNumber numberWithBool:isFrontmost]; NSDictionary * dict = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:processID, processName,appId,isFrontmostN, nil] forKeys:[NSArray arrayWithObjects:@"ProcessID", @"ProcessName",@"AppID",@"isFrontmost", nil]]; NSLog(@"PID:%@, name: %@, AppID:%@,isFrontmost:%d",processID,processName,appId,isFrontmost); [array addObject:dict]; } } } free(process); return array; } } } dlclose(sbserv); }