0

I have an app in which on viewController i have a simple webView and i am loading my website say https://mywebsite.com

Now i want to send device token to the same website as cookie but for some reason i could not access the deviceToken in viewDidLoad method.

Code is as per below of viewController.m

- (void)viewDidLoad {

     NSUserDefaults *deviceInfo = [NSUserDefaults standardUserDefaults];

     NSString *deviceID = [deviceInfo objectForKey:@"deviceToken"];

    [super viewDidLoad];
    NSURL *url=[NSURL URLWithString:@"http://staging.mywebsite.com"];
    NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url];


    NSArray * cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
    NSDictionary * headers = [NSHTTPCookie requestHeaderFieldsWithCookies: cookies];

    NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary];
    [cookieProperties setObject:@"deviceToken" forKey:NSHTTPCookieName];
    [cookieProperties setObject:deviceID forKey:NSHTTPCookieValue];
    [cookieProperties setObject:@"staging.mywebsite.com" forKey:NSHTTPCookieDomain];
    [cookieProperties setObject:@"staging.mywebsite.com" forKey:NSHTTPCookieOriginURL];

    [cookieProperties setObject:[[NSDate date] dateByAddingTimeInterval:2629743] forKey:NSHTTPCookieExpires];

    NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
    [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];

    [request setHTTPMethod:@"Post"];
    [request setHTTPShouldHandleCookies:YES];
    [request setAllHTTPHeaderFields:headers];


    [_webView loadRequest:request];
}

I have added following code in method didRegisterForRemoteNotificationsWithDeviceToken

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{

    NSString *strDevicetoken = [[NSString alloc]initWithFormat:@"%@",[[[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]] stringByReplacingOccurrencesOfString:@" " withString:@""]];

    NSUserDefaults *deviceInfo = [NSUserDefaults standardUserDefaults];

    [deviceInfo setObject:strDevicetoken forKey:@"deviceToken"];

    [deviceInfo synchronize];

}

It still doesnt work on real device. What wrong am i doing here?

Thank you

Mike Ross
  • 2,942
  • 5
  • 49
  • 101
  • AppDelete does not have a member variable called strDeviceToken so you will be getting a compiler error I presume. There's several things you could do, one would be to store it to NSUserDefaults in the delegate and read it from there in the controller. – Gruntcakes Jan 04 '17 at 00:08
  • @DonaldTrumpatemyhamster i have updated the code in question. Please tell me how to access that variable `token` in `viewDidLoad` method. – Mike Ross Jan 04 '17 at 00:10
  • For every set method there is a corresponding get method. – Gruntcakes Jan 04 '17 at 00:17
  • @DonaldTrumpatemyhamster I did use `NSUserDefaults ` like you said but still it doesnt work. I have edited the code. – Mike Ross Jan 04 '17 at 00:37
  • have you check that you are actually able to get the device token? have you put a break point – Joshua Jan 04 '17 at 01:40
  • @Joshua I am not sure how to check because in simulator devicetoken doesnt work i guess. But when i install the app it do ask for the permission to receive notification. How else can i check it? – Mike Ross Jan 04 '17 at 01:42
  • connect your device and debug from there. then put a breakpoint on did registerforremote ... check the strDeviceToken value – Joshua Jan 04 '17 at 01:49
  • @Joshua Yes i tried what you said. I do get the deviceToken but from debug session i can say that `viewDidLoad` function is executed first and `AppDelegate.didRegisterForRemoteNotificationsWithDeviceToken` executed later on. Anyway around it ? – Mike Ross Jan 04 '17 at 01:54
  • well, you can take a look at notification wherein if you managed to receive the deviceRegistration you can send a notification informing the VC or use delegation. then reload the webView after the notification/delegate call – Joshua Jan 04 '17 at 02:10
  • @Joshua I did not fully understand what you meant about VC or delegation. But i think reloading `UIwebView` doesnt seem like good programming. Website inside webview will be loaded first and after receiving deviceToken reloaded,dont like the idea of that. Is there any other option? – Mike Ross Jan 04 '17 at 02:16
  • those are just my two cents. VC = viewController. I am not really sure what your webView is doing I just assumed that reloading a page with the needed param will be ok. you can also wait for it before actually initialising a webView – Joshua Jan 04 '17 at 02:53
  • @Joshua how can i wait for it before initialising a webView?? – Mike Ross Jan 04 '17 at 03:00
  • @MikeRoss Use block. – felixwcf Jan 04 '17 at 06:44
  • @Felix thank you for your input but my problem now is with lifecycle of app which executed `ViewController` first and then `AppDelegate.didRegisterForNotification` method. So my webview is loaded first and i get the devicetoken later on. – Mike Ross Jan 04 '17 at 06:57
  • How to "wait" for token before initialising a webView: Use NSNotificationCenter (broadcast - receiver) pattern to send the token to your vc which has the webview, from app delegate. Once received token in your vc, add it to cookies, request the website. Put loading indicator while waiting for the token. I've updated my answer below. – felixwcf Feb 23 '17 at 06:35

1 Answers1

1

Your current situation is when you register for remote notification in app delegate and before didRegisterForRemoteNotificationsWithDeviceToken is called, you have already initiate your view controller (VC) and viewDidLoad method is being called before you get the device token.

Your app flow should be like this

i. In app delegate didFinishLaunchingWithOptions method, register remote notification.

ii. Within a second, in didRegisterForRemoteNotificationsWithDeviceToken callback function, you should receive the device token.

iii. If you initiate your view controller in app delegate, you can make a public function in your view controller:

- (void)requestWebViewWithToken:(NSString *)token {
    // You code - storing token in cookies and request webview. 
}

iv. Call the function in didRegisterForRemoteNotificationsWithDeviceToken ONLY when you get the token. There's so many options. You can use NSNotificationCenter, custom delegate, public method (as mentioned above), or static method.

"But i think reloading UIwebView doesnt seem like good programming. Website inside webview will be loaded first and after receiving deviceToken reloaded,dont like the idea of that"

Reloading webview when you need to, not being redundant, is acceptable. For your case, you can show and animate activity indicator view (loading indicator) in viewDidLoad.

Load the webview only when you receive the token. It just take 1 second to get the token, so waiting to load the webview after you get the token won't causing user experience defect.

Lastly, you might need to handle the situation where user did not turn on to receive push notification, or no Internet connection etc...


Solution:

  1. In AppDelegate.m, in your didRegisterForRemoteNotificationsWithDeviceToken delegate,

    [[NSNotificationCenter defaultCenter] postNotificationName:@"device_token_notification"
                                                        object:nil
                                                      userInfo:@{@"token":@"8057b9be2a0caa8802034369fc6035aac9c577180xxxx"}];
    
  2. In your vc which contains the webview, in your viewDidLoad method, add this code:

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(requestWebView:)
                                             name:@"device_token_notification"
                                           object:nil];
    

and create the method

- (void)requestWebView:(NSNotification *)noti {
    NSDictionary *dict = [noti userInfo];
    NSString *deviceToken = dict[@"token"];

    // Store token into cookies.
    // Request your web.
}

Remember to remove the receiver when you don't need it.

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:@"device_token_notification"];
}
Community
  • 1
  • 1
felixwcf
  • 2,078
  • 1
  • 28
  • 45