关于如何将 APN 的设备令牌链接到注册用户的建议(通过 phonegap 或 UIWebView)

Posted

技术标签:

【中文标题】关于如何将 APN 的设备令牌链接到注册用户的建议(通过 phonegap 或 UIWebView)【英文标题】:Suggestion on how to link APN's device token to a registered user (through phonegap or UIWebView) 【发布时间】:2012-02-23 04:12:17 【问题描述】:

这里有类似的问题:jQueryMobile, Phonegap and Device Token - ios

场景是,我有这个基于 Web 的 PhoneGap 应用程序,原生 iOS 帮助我在 APN 上注册了设备,并且我在服务器数据库中收到了设备令牌。

问题 1:如何使用 PhoneGap 将注册用户(通过 UIWebView)关联到此设备令牌?

我现在的想法是编写一个自定义插件并在用户注册期间传递设备令牌。有没有更好的选择?

问题 2: 由于 device_token 可以不时更改,我应该如何将此用户重新链接到此 device_token?

也许每当用户登录时,我都会做一个 window.plugins.PluginName.getDeviceToken 并同步它? user_id:123, old_device_token: 'xxxx..', new_device_token: 'xxx...'?

仅供参考,此应用程序是为一个活动而构建的,客户已请求在此移动应用程序上进行人与人之间的消息传递。当“John Doe”收到朋友的消息时,如何向他推送新消息通知? - 问题是如何将“John Doe”链接到特定的 device_token?

这不能太针对 iOS,因为该应用程序也必须部署在 android 上 (C2DM)。

欢迎任何帮助!

编辑:可能的解决方案?

不安的研究出现了这个可能的解决方案:

    [Native] 应用程序已启动 - APN 注册已启动并收到 device_token [Native] 将此 device_token 存储到本地存储(CoreData/SqlLite 或 Property Lists?)并将其发送到服务器以进行 device_token 注册 [WebView] 每当用户登录或注册时,此 device_token 将通过 PhoneGap 进行查询、哈希处理并发送到服务器进行登录、比较和链接。

任何不可预见的情况是有问题的?

编辑:回答

我在答案中发布了完整的工作解决方案。在这里查看:https://***.com/a/9628592/534862

【问题讨论】:

你是否在插件或其他可以传递给 PhoneGap 的东西上取得了进展? 还没有。我还在做这个项目,一旦我得到一些东西,我会在这里发布 您是否设法使我的解决方案发挥作用? 是的,经过一整天的探索,今天晚上才开始工作。我已将其转换为 Cordova,现在可以完美运行。接受了你的回答。我稍后会发布我的解决方案 【参考方案1】:

为了完整起见,这是我使用@TDeBailleul 解决方案后的解决方案。移植到科尔多瓦。 (仅在 iOS 上测试。完成 Android 版本后,我将为此发布一个插件:

环境

Cordova 1.5.0(以前的 PhoneGap) Xcode 4.3.1 iOS 5.1 Mac OS X 10.7.3 不要使用自动引用计数 (ARC) 以避免编译错误 通过this freaking long tutorial 准备好您的推送通知证书

工作流程

    [Native] 应用程序已启动 - APN 注册已启动,并且在服务器端接收到 device_token [Native] 应用程序将令牌存储在AppDelegate,要获取令牌,请在以下代码中使用PushToken [WebView] 每当用户登录或注册时,令牌将通过 Cordova(以前称为 PhoneGap)插件调用、散列并发送到服务器以进行登录、匹配并将用户链接到特定设备。

所以下面是我的完整的工作代码,这些代码可以本地提取令牌。服务器部分只是将帐户链接到设备。你应该知道如何通过你最喜欢的服务器端应用程序来做到这一点。

AppDelegate.h

@interface AppDelegate : NSObject < UIApplicationDelegate, UIWebViewDelegate, CDVCommandDelegate > 
    ...
    NSString* token;
    ...

...
...
...
@property (retain, nonatomic) NSString* token;

AppDelegate.m

注意:我是 Obj-C 新手,我也尝试将令牌发布到我的服务器。如果不需要发帖机制,保留didRegisterForRemoteNotificationsWithDeviceToken中的前5行(直到'self.token = dt

...

@synthesize token;

...

- (BOOL) application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
    
...
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:
    (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];

    return YES;


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

    NSLog(@"Did finish launching with device token %@", deviceToken);
    NSString *dt = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
    dt = [dt stringByReplacingOccurrencesOfString:@" " withString:@""];

    self.token = dt;

    NSString *dv = [[UIDevice currentDevice] systemVersion];
    NSString *dn = [[UIDevice currentDevice] systemName];
    NSString *nick = [[UIDevice currentDevice] name];
    NSString *model = [[UIDevice currentDevice] model];
    NSString *uniqueIdentifier = [[UIDevice currentDevice] uniqueIdentifier];

    NSMutableString *postData = [NSMutableString stringWithString: @"&deviceToken="];

    [postData appendString:dt];
    [postData appendFormat:@"&uniqueIdentifier=%@&application_uuid=5ade8400-e29c-41d4-a716-3641972a2ec6", uniqueIdentifier];
    [postData appendFormat:@"&source=ios&name=%@&model=%@&systemName=%@&systemVersion=%@", nick, model, dn, dv];

    NSString* escapedURLString = [postData stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

    @try 
        NSData *postData = [escapedURLString dataUsingEncoding:NSUTF8StringEncoding];
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
                                        initWithURL: [NSURL URLWithString:@"YOUR URL TO POST TOKEN TO SERVER"]
                                        cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval: 180];
        NSString *postLength = [[NSString alloc] initWithFormat: @"%d", [postData length]];
        [request setHTTPMethod:@"POST"];
        [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
        [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
        [request setHTTPBody:postData];


        NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
        if (conn) 
            //??
        else
            //??
        
    
    @catch (NSException *exception) 
        NSLog(@"Exception %@", exception);
    

...

PushToken.h

#import <Foundation/Foundation.h>
#import <CORDOVA/CDVPlugin.h>

@interface PushToken : CDVPlugin 
    NSString* callbackID;


@property (nonatomic, copy) NSString* callbackID;

- (void) getToken:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;

@end

PushToken.m

#import "PushToken.h"
#import "AppDelegate.h"

@implementation PushToken

@synthesize callbackID;

- (void)getToken:(NSMutableArray *)arguments withDict:(NSMutableDictionary *)options 

    NSLog(@"Did called getToken");
    self.callbackID = [arguments pop];

    NSString *token = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).token;
    CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[token stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

    if (token.length != 0) 
        [self writejavascript: [pluginResult toSuccessCallbackString:self.callbackID]];
    else
        [self writeJavascript: [pluginResult toErrorCallbackString:self.callbackID]];
    


@end

PushToken.js

var PushToken = 
    /**
    * Get token from the device
    * @param array types - By default is ['getToken']
    * @param function success Success callback, with token
    * @param function fail Failure callback, with null
    */
    getToken: function(types, success, fail) 
        return Cordova.exec(success, fail, "PushToken", "getToken", types);
    ,

    /**
    * For the sake of iOS, we need an install function
    */
    install: function() 
        window.plugins = window.plugins || ;
        window.plugins.PushToken = PushToken;
    
;

/**
* For the rest of the devices
*/
window.plugins = window.plugins || ;
window.plugins.PushToken = PushToken;

用法

document.addEventListener('deviceready', function() 
    if (typeof PushToken == 'object') 
        PushToken.install();
    

    PushToken.getToken(['getToken'], function(token) 
        callback(token);
    , function() 
        callback(null);
    );
);

你应该能够从你的 Javascript 端获取你的令牌;)

玩得开心!

干杯

【讨论】:

【参考方案2】:

前面的答案确实是解决这个问题的好方法,而且他们以非常正式的方式解决了这个问题。但是,如果您想要一种快速而肮脏的方法来解决问题,您可以简单地这样做:

在 didRegisterForRemoteNotificationsWithDeviceToken 底部添加

NSString* jsString = [NSString stringWithFormat:@"var deviceToken = \"%@\";", deviceToken];
[self.viewController.webView stringByEvaluatingJavaScriptFromString:jsString];

在您的 javascript 中

deviceId = (typeof deviceToken !== "undefined") ? deviceToken : null;

【讨论】:

这个去哪儿了? didRegisterForRemoteNotificationsWithDeviceToken 有多个实例。【参考方案3】:

好的,我终于做了一个似乎可以工作的插件

1 - 确保您的 PhoneGap Xcode 项目已针对 iOS 4 SDK 进行了更新。

2 - 在您的 Plugins 文件夹中创建一个 PushToken 文件夹,将以下 PushToken.m 和 PushToken.h 文件添加到其中,然后使用“为任何添加的文件夹创建组”将该文件夹拖到 XCode 中的 Plugin 文件夹中

3 - 将 PushToken.js 文件添加到磁盘上的 www 文件夹,并将 .js 文件的引用添加为 html 文件中的标记

4 - 在 PhoneGap.plist 中的插件中添加带有 PushToken 键和字符串值 PushToken 的新条目

PushToken.h

#import <Foundation/Foundation.h>
#import <PhoneGap/PGPlugin.h>

@interface PushToken : PGPlugin

    NSString* callbackID;  


@property (nonatomic, copy) NSString* callbackID;

- (void) getToken:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;

@end

PushToken.m

#import "PushToken.h"
#import "AppDelegate.h"

@implementation PushToken

@synthesize callbackID;

-(void)getToken:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options  
    self.callbackID = [arguments pop];

    NSString *token = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).token;
    PluginResult* pluginResult = [PluginResult resultWithStatus:PGCommandStatus_OK messageAsString:[token stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

    if(token.length != 0)
    
        [self writeJavascript: [pluginResult toSuccessCallbackString:self.callbackID]];
    else     
        [self writeJavascript: [pluginResult toErrorCallbackString:self.callbackID]];
    


@end

PushToken.js

var PushToken = 
    getToken: function(types, success, fail) 
        return PhoneGap.exec(success, fail, "PushToken", "getToken", types);
    
;

如何使用

PushToken.getToken(     
    ["getToken"] ,           
    function(token) 
        console.log("Token : "+token); 
    ,
    function(error) 
        console.log("Error : \r\n"+error);      
    
);

AppDelegate.h

@interface AppDelegate : PhoneGapDelegate 
    NSString* invokeString;
    NSString* token;


@property (copy)  NSString* invokeString;
@property (retain, nonatomic) NSString* token;

AppDelegate.m

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

    self.token = [[[[deviceToken description]
                         stringByReplacingOccurrencesOfString: @"<" withString: @""]
                        stringByReplacingOccurrencesOfString: @">" withString: @""]
                       stringByReplacingOccurrencesOfString: @" " withString: @""];

    NSLog(@"My token is: %@", self.token);

我让它在 PhoneGap 1.1 上运行

希望对你有帮助

【讨论】:

添加答案作为我的下一篇文章;) 那么在 xcode 中不是 plugins 文件夹的 plugins 文件夹在哪里?

以上是关于关于如何将 APN 的设备令牌链接到注册用户的建议(通过 phonegap 或 UIWebView)的主要内容,如果未能解决你的问题,请参考以下文章

iOS APN 推送通知 - 设备令牌

多用户的 APN 设备令牌

为 APN 安全发送设备令牌

如何注册 iOS 设备以接收推送通知?

从 APN 迁移到 Firebase 后未重新生成 iOS 设备令牌

取消订阅 Apple 推送通知服务