Enterprise App Crashes after Install from MDM

2019-07-26 14:24发布

We have an iOS 9.2 app that runs fine in testing when installed via Xcode and the local Mac. When we install this application through our MDM server it crashes on the first access of data. It is exiting with the error "failed to scene-update after 10.00s."

I from checking the console output, it appears to be hanging up after the success process in the requireLogin method (after the [self checkIntSession:self.sessionDetail].

We are using Novell's MDM not the Apple version. I have created other applications that have installed and run with no problems.

I have tried a clean build and install. It did not help. I cannot find an similar question answered here or anywhere else. I'm at a loss for where to go with this next. Any help would be appreciated.

#import "Security.h"
#import "XMLTypeItem.h"
#import "ParseTypeXML.h"
#import "XMLPostSecurity.h"
#import "XMLSessionItem.h"
#import "FileSaving.h"
#import <LocalAuthentication/LocalAuthentication.h>

@implementation Security

- (NSString *)retrieveESN {

    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectoryPath = [directoryPaths objectAtIndex:0];
    NSString *fullPath = [documentsDirectoryPath stringByAppendingString:@"/session.txt"];
    if ([fileManager fileExistsAtPath:fullPath]==YES) {
        _finished = false;
        [self readSession];
        NSString *result = [self checkSession:_sessionDetail];
        if ([result isEqualToString:@"Error"]) {
            NSString *userESN = [self newFile];


            if (self.getUserESN){
                self.getUserESN(userESN);
            }

            return userESN;
        } else {
            return result;
        }
    } else {
        _finished = false;
        NSString *userESN = [self newFile];
        return userESN;
    }
}

- (NSString *)newFile {
    [self requireLogin];

    if (self.findUserESN) {
        self.findUserESN(_passESN);
    }

    return _passESN;
}


- (void)requestSession {
    NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    NSString *url = @"https://company.com/loginfile";

    NSMutableString *postText = [[NSMutableString alloc] init];

    [postText appendString:idfv];

    NSString *postBody = [NSString stringWithString:postText];

    XMLPostSecurity *postAction = [[XMLPostSecurity alloc] init];
    _sessionDetail = [postAction sendPostRequestToUrl:url withBody:postBody];

    FileSaving *saver = [[FileSaving alloc] init];

    [saver saveSession:self.sessionDetail];
}

-(NSString *)readSession {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectoryPath = [directoryPaths objectAtIndex:0];
    NSString *fullPath = [documentsDirectoryPath stringByAppendingString:@"/session.txt"];

    if (self.fileExistsNow) {
        self.fileExistsNow([fileManager fileExistsAtPath:fullPath]);
    }

    NSFileManager *fileManagerTwo;
    NSData *dataBuffer;
    fileManagerTwo = [NSFileManager defaultManager];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *filePath = [documentsDirectory stringByAppendingString:@"/session.txt"];

    dataBuffer = [fileManagerTwo contentsAtPath:filePath];
    _sessionDetail = [[NSString alloc] initWithData:dataBuffer encoding:(NSASCIIStringEncoding)];

    return _sessionDetail;
}

-(void)readIntSession {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectoryPath = [directoryPaths objectAtIndex:0];
    NSString *fullPath = [documentsDirectoryPath stringByAppendingString:@"/session.txt"];

    if (self.fileExistsNow) {
        self.fileExistsNow([fileManager fileExistsAtPath:fullPath]);
    }

    NSFileManager *fileManagerTwo;
    NSData *dataBuffer;
    fileManagerTwo = [NSFileManager defaultManager];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *filePath = [documentsDirectory stringByAppendingString:@"/session.txt"];

    dataBuffer = [fileManagerTwo contentsAtPath:filePath];
    _sessionDetail = [[NSString alloc] initWithData:dataBuffer encoding:(NSASCIIStringEncoding)];
}

-(NSString *)checkSession:(NSString *)sessionFound {
    NSDictionary *cookieProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                      @"ollie/", NSHTTPCookieDomain,
                                      @"\\", NSHTTPCookiePath,
                                      @"Cookie", NSHTTPCookieName,
                                      sessionFound, NSHTTPCookieValue,
                                      nil];
    NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
    NSArray *cookieArray = [NSArray arrayWithObject:cookie];
    NSDictionary *headers = [NSHTTPCookie requestHeaderFieldsWithCookies:cookieArray];

    NSMutableString *url = [[NSMutableString alloc] initWithString:@"https://company.com/file.php"];

    NSURL *urlNew = [NSURL URLWithString:url];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:urlNew];
    [request setHTTPMethod:@"GET"];
    [request setAllHTTPHeaderFields:headers];

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

                                                if (error) {
                                                    return;
                                                }

                                                if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
                                                    NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];

                                                    if (statusCode != 200) {

                                                        if (statusCode == 401) {
                                                            // Insert process for thumbprint and session cookie pull

                                                            NSFileManager *fileManagerThree = [NSFileManager defaultManager];
                                                            NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
                                                            NSString *sessionPath = [documentsPath stringByAppendingPathComponent:@"session.txt"];
                                                            NSError *error;
                                                            BOOL success = [fileManagerThree removeItemAtPath:sessionPath error:&error];
                                                            if (success) {
                                                            } else {
                                                            }
                                                        } else {
                                                            return;
                                                        }
                                                    }
                                                }
                                                self.parseData = data;
                                            }];
    [task resume];

    if (self.parseDataAvailable) {
        self.parseDataAvailable(self.parseData);
    }

    ParseTypeXML *myParser = [[ParseTypeXML alloc] initWithData:self.parseData];
    if ([myParser.esn count] == 0) {
        return @"Error";
    } else {
        return myParser.esn[0];
    }
}

-(void)checkIntSession:(NSString *)sessionFound {
    NSDictionary *cookieProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                      @"ollie/", NSHTTPCookieDomain,
                                      @"\\", NSHTTPCookiePath,
                                      @"Cookie", NSHTTPCookieName,
                                      sessionFound, NSHTTPCookieValue,
                                      nil];
    NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
    NSArray *cookieArray = [NSArray arrayWithObject:cookie];
    NSDictionary *headers = [NSHTTPCookie requestHeaderFieldsWithCookies:cookieArray];

    NSMutableString *url = [[NSMutableString alloc] initWithString:@"https://company.com/file.php"];

    NSURL *urlNew = [NSURL URLWithString:url];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:urlNew];
    [request setHTTPMethod:@"GET"];
    [request setAllHTTPHeaderFields:headers];

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

                                                if (error) {
                                                    return;
                                                }

                                                if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
                                                    NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];

                                                    if (statusCode != 200) {

                                                        if (statusCode == 401) {
                                                            // Insert process for thumbprint and session cookie pull

                                                            NSFileManager *fileManagerThree = [NSFileManager defaultManager];
                                                            NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
                                                            NSString *sessionPath = [documentsPath stringByAppendingPathComponent:@"session.txt"];
                                                            NSError *error;
                                                            BOOL success = [fileManagerThree removeItemAtPath:sessionPath error:&error];
                                                            if (success) {
                                                            } else {
                                                            }
                                                        } else {
                                                            return;
                                                        }
                                                    }
                                                }
                                                self.parseData = data;
                                            }];
    [task resume];

    if ( self.parseDataAvailable) {
        self.parseDataAvailable(self.parseData);
    }

    ParseTypeXML *myParser = [[ParseTypeXML alloc] initWithData:self.parseData];
    if ([myParser.esn count] == 0) {
        _passESN = @"Error";
    } else {
        _passESN = myParser.esn[0];
    }
}

- (void)requireLogin {

    LAContext *context = [[LAContext alloc] init];
    NSError *error = nil;

    if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
        // Authenticate User
        [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
                localizedReason:@"You must log in to the app."
                          reply:^(BOOL success, NSError * _Nullable error) {

                              if (success) {
                                  self.finished = true;
                                  if (self.touchIDWorks){
                                      self.touchIDWorks(self.finished);
                                  }
                                  [self requestSession];
                                  [self readIntSession];
                                  [self checkIntSession:self.sessionDetail];
                              } else {
                                  switch (error.code) {
                                      case LAErrorAuthenticationFailed:
                                          break;
                                      case LAErrorUserCancel:
                                          break;
                                      case LAErrorUserFallback:
                                          break;

                                      default:
                                          break;
                                  }
                              }
                          }];
    } else {
    }
}

- (void)dataIsThere:(void (^)(NSData *foundData))finishBlock {
    self.parseDataAvailable = finishBlock;
}

- (void)thumbOK:(void (^)(BOOL success))finishBlock {
    self.touchIDWorks = finishBlock;
}

- (void)esnIsHere:(void (^)(NSString *newESN))finishBlock {
    self.getUserESN = finishBlock;
}

- (void)esnIsReady:(void (^)(NSString *))finishBlock {
    self.findUserESN = finishBlock;
}

- (void)fileReady:(void (^)(BOOL))finishBlock {
    self.fileExistsNow = finishBlock;
}

It is called from ViewController.m:

- (IBAction)getESN:(id)sender {
    Security *pulledESN = [[Security alloc] init];
    self.gottenESN = [pulledESN retrieveESN];
    self.responseLabel.text = self.gottenESN;
}

=== Later Add ===

Putting in the completion blocks has not resolved the problem. The code still seems to hang after completing the requireLogin success section. Like I need a return or something.

1条回答
闹够了就滚
2楼-- · 2019-07-26 14:32

This line looks super scary to me:

  while ( self.parseData == NULL );

It might be a debug vs. release build issue. I could imagine a release version optimizing the read of self.parseData to not keep checking if other threads have updated it.

I recommend that you do this some other way -- polling in a loop like this pegs the CPU at 100% while it's waiting. I would suggest writing it to be asynchronous with completion blocks that you call when the data is ready.

查看更多
登录 后发表回答