Ionic Pro: Deploy app crashes on load


#1

Hello,

Because Ionic Deploy Legacy is broken, I have to update to Ionic Pro earlier than I would like to.

However Ionic Pro deploy is also broken.

I am manually downloading the new snapshot/version. It downloads fine. When the app is closed and relaunched, the app crashes - and it’s related to [IonicDeploy_doRedirect]

Here is the error in XCode:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSRegularExpression enumerateMatchesInString:options:range:usingBlock:]: nil argument'

Here is the error call stack:
*** First throw call stack:
(
	0   CoreFoundation                      0x00000001097d71cb __exceptionPreprocess + 171
	1   libobjc.A.dylib                     0x0000000108cd4f41 objc_exception_throw + 48
	2   CoreFoundation                      0x000000010984bb95 +[NSException raise:format:] + 197
	3   Foundation                          0x00000001086d5b05 -[NSRegularExpression(NSMatching) enumerateMatchesInString:options:range:usingBlock:] + 203
	4   Foundation                          0x00000001086d5a28 -[NSRegularExpression(NSMatching) matchesInString:options:range:] + 151
	5   WFA CPGs                            0x0000000108140ba8 __25-[IonicDeploy doRedirect]_block_invoke + 1320
	6   libdispatch.dylib                   0x000000010d2463f7 _dispatch_call_block_and_release + 12
	7   libdispatch.dylib                   0x000000010d24743c _dispatch_client_callout + 8
	8   libdispatch.dylib                   0x000000010d24f95b _dispatch_queue_serial_drain + 1162
	9   libdispatch.dylib                   0x000000010d2502df _dispatch_queue_invoke + 336
	10  libdispatch.dylib                   0x000000010d24c07d _dispatch_queue_override_invoke + 733
	11  libdispatch.dylib                   0x000000010d2531f9 _dispatch_root_queue_drain + 772
	12  libdispatch.dylib                   0x000000010d252e97 _dispatch_worker_thread3 + 132
	13  libsystem_pthread.dylib             0x000000010d7db5a2 _pthread_wqthread + 1299
	14  libsystem_pthread.dylib             0x000000010d7db07d start_wqthread + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException

My Ionic Info is:

Chriss-MBP:wfcpg chrisdelambert$ ionic info

cli packages: (/Users/chrisdelambert/Documents/wfcpg/node_modules)

@ionic/cli-utils  : 1.12.0
ionic (Ionic CLI) : 3.12.0

global packages:

cordova (Cordova CLI) : 7.0.1 

local packages:

@ionic/app-scripts : 2.1.4
Cordova Platforms  : android 6.2.3 ios 4.4.0
Ionic Framework    : ionic-angular 3.6.0

System:

Android SDK Tools : 26.0.2
ios-deploy        : 1.9.2 
ios-sim           : 6.0.0 
Node              : v8.1.4
npm               : 5.1.0 
OS                : macOS Sierra
Xcode             : Xcode 9.0 Build version 9A235 

Misc:

backend : pro

I haven’t tried android yet so for now this is an ios problem. Has anyone encountered this and found a work around. At this stage both Legacy deploy and Pro deploy are useless. Also, the docs for Ionic Pro are hopeless - none of the links work. Come on Ionic Team. If you are going to charge us now, at least sort the basics out…


#2

I have limited experience programming directly for iOS, but am wondering if you’re using any sort of location tracking, mapping, or push services. What experience I do have working with hands-on iOS, those NS strings are a constant source of contention. Especially the locations services and push stuff, combined with developers certificates, provisioning profiles, etc.

Though, generally when recieving an error based on an NSString, it’s an issue with your code. Somewhere in your app, you may be trying to initiate some attribute with a string that does not exist, or some string that should have some attribute. That may explain the ‘nil arguement’ statement
here

 [NSRegularExpression enumerateMatchesInString:options:range:usingBlock:]: nil argument’

Though I have observed alot of growing pains with Ionic transitioning to Pro, I don’t think they provide fixes for potentially faulty coding. That’s for us to figure out on our own.

If i’m wrong on this one, I promise to punch myself in the face.

FYI, the references to Foundation, CoreFoundation, are iOS terms, not Ionic terms. Foundation is an iOS ‘library’ that allows your app access to things like NSStrings, NSObjects, NSUrls. Further suggesting there is a coding issue within your app.


#3

Ionic Pro is a hosted and closed source service, so there is not much we, the community, can help you with, sorry. Check these:

You can - and should - contact support at http://ionicframework.com/support#support


#4

Hi,

Cheers for your reply. In XCode, the block of code throwing the error is this:

// Ensure cordova.js isn’t commented out
NSRegularExpression *commentedRegex = [NSRegularExpression
regularExpressionWithPattern:@""
options:NSRegularExpressionCaseInsensitive
error:&error];

The error is:
*** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘*** -[NSRegularExpression enumerateMatchesInString:options:range:usingBlock:]: nil argument’

I have no idea what this means but I guess my point is I’m not sure how my code is affecting this code in IonicDeploy.m.

The comments say it’s code for checking if cordova.js script tag is commented out (line 524 in IonicDeploy.m

Can someone with ios knowledge can help explain what is happening here, please do :slight_smile:


#5

Are you by chance doing any comparing of strings in your app? Checking to see if a word, words, or a sentence exists?

Or a compare function that includes toLowerCase() or toUpperCase()?

I’m looking into it, just for curiousity’s sake. I might end up having to punch myself in the face…


#6

I’m not but the plugin obviously is. I assume it is checking the uuid of the current and new snapshots.

From what I understand the code that isn’t working is checking if the script tag for cordova.js exists, or if it is commented out. Annoying part is I don’t even need or want this check but I don’t know enough about C to remove the code. Whatever I change will also be overwritten every time the plugin is updated.

For reference here is the method that causes the error.

  • (void) doRedirect {
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    NSString *uuid = [[NSUserDefaults standardUserDefaults] objectForKey:@“uuid”];
    NSString *ignore = [prefs stringForKey:@“ionicdeploy_version_ignore”];
    if (ignore == nil) {
    ignore = NOTHING_TO_IGNORE;
    }

    NSLog(@“uuid is: %@”, uuid);
    if (self.ignore_deploy) {
    NSLog(@“ignore deploy”);
    }

    NSLog(@“ignore version: %@”, ignore);
    if (![uuid isEqualToString:@""] && !self.ignore_deploy && ![uuid isEqualToString:ignore]) {
    dispatch_async(self.serialQueue, ^{
    if ( uuid != nil && ![self.currentUUID isEqualToString: uuid] ) {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
    NSString *libraryDirectory = [paths objectAtIndex:0];
    NSString *query = [NSString stringWithFormat:@“cordova_js_bootstrap_resource=%@”, self.cordova_js_resource];

              NSURLComponents *components = [NSURLComponents new];
              components.scheme = @"file";
              components.path = [NSString stringWithFormat:@"%@/%@/index.html", libraryDirectory, uuid];
              components.query = query;
    
              self.currentUUID = uuid;
    
              // Load the target index.html and init values
              NSString *htmlData = [NSString
                                    stringWithContentsOfFile:components.path
                                    encoding:NSUTF8StringEncoding
                                    error:nil];
              NSString *newReference = [NSString
                                        stringWithFormat:@"<script src=\"%@\"></script>", self.cordova_js_resource];
              NSError *error = nil;
    
              // Ensure cordova.js isn't commented out
              NSRegularExpression *commentedRegex = [NSRegularExpression
                                                     regularExpressionWithPattern:@"<!--.*<script src=(\"|')(.*\\/|)cordova\\.js.*(\"|')>.*<\\/script>.*-->"
                                                     options:NSRegularExpressionCaseInsensitive
                                                     error:&error];
              NSArray *matches = [commentedRegex
                                  matchesInString:htmlData
                                  options:0
                                  range:NSMakeRange(0, [htmlData length])];
              if (matches && matches.count){
                  // It was commented out, uncomment and update it.
                  htmlData = [commentedRegex
                              stringByReplacingMatchesInString:htmlData options:0
                              range:NSMakeRange(0, [htmlData length])
                              withTemplate:newReference];
              } else {
                  // We need to inject the script tag and/or update an existing one.
                  // First, find an existing cordova.js tag
                  NSRegularExpression *cordovaRegex = [NSRegularExpression
                                                       regularExpressionWithPattern:@"<script src=(\"|')(.*\\/|)cordova\\.js.*(\"|')>.*<\\/script>"
                                                       options:NSRegularExpressionCaseInsensitive
                                                       error:&error];
                  matches = [cordovaRegex matchesInString:htmlData options:0 range:NSMakeRange(0, [htmlData length])];
                  if (matches && matches.count){
                      // We found the script, update it
                      htmlData = [cordovaRegex
                                  stringByReplacingMatchesInString:htmlData
                                  options:0
                                  range:NSMakeRange(0, [htmlData length])
                                  withTemplate:newReference];
                  } else {
                      // cordova.js isn't present, need to inject. We'll just put it after the first <script> tag we find
                      NSRegularExpression *scriptRegex = [NSRegularExpression
                                                          regularExpressionWithPattern:@"<script.*>.*</script>"
                                                          options:NSRegularExpressionCaseInsensitive
                                                          error:&error];
                      NSTextCheckingResult *match = [scriptRegex
                                                     firstMatchInString:htmlData
                                                     options:NSRegularExpressionCaseInsensitive
                                                     range:NSMakeRange(0, [htmlData length])];
    
                      // Add our script after the one we matched
                      NSString *injectedScript = [NSString stringWithFormat:@"%@\n%@\n", [htmlData substringWithRange:[match rangeAtIndex:0]], newReference];
                      // Update the index.html string with our script
                      htmlData = [htmlData
                                  stringByReplacingOccurrencesOfString:[htmlData substringWithRange:[match rangeAtIndex:0]]
                                  withString:injectedScript];
                  }
              }
    
    
              // Write new index.html
              [htmlData writeToFile:components.path atomically:YES encoding:NSUTF8StringEncoding error:nil];
    
              // Do redirect
              NSLog(@"Redirecting to: %@", components.URL.absoluteString);
              dispatch_async(dispatch_get_main_queue(), ^(void){
                  NSLog(@"Reloading the web view.");
                  SEL reloadSelector = NSSelectorFromString(@"reload");
                  ((id (*)(id, SEL))objc_msgSend)(self.webView, reloadSelector);
                  [self.webViewEngine loadRequest:[NSURLRequest requestWithURL:components.URL]];
              });
          }
      });
    

    }
    }


#7

A sick sense of humor was behind that code for sure. My sympathy. If I run across anything that can help you, I’ll surely let you know.


#8

Haha yeah. Deploy works fine on android devices. This problem is only on ios. I really hope they fix it. At the moment both the legacy deploy and the pro deploy are unusable.


#9

Yeah, Apple has been notoriously difficult for me to contend with. I suppose having a Mac would help…but, trying to navigate Apple’s process is kind of extremely frustrating. The apparent missteps between Ionic and Apple are unfortunate, but im not about to reboot Netbeans any time soon.


#10

@media4learning To address this issue remove the cordova-ionic-plugin using ionic cordova plugin rm cordova-ionic-plugin .