6

我使用推送通知并存储设备令牌,就像我假设其他人一样。首先,我将它们转换为我的应用程序的字符串:

NSString *deviceTokenString = [[[token description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]]
                               stringByReplacingOccurrencesOfString:@" " withString:@""];

然后我把它们放到我的服务器上,ActiveRecord 将它们存储在一个character varying(255)列中:

Device.where(:token => device_token, :username => username).first_or_create!(:model => model)

我有一个验证可以确保没有两个令牌是相同的,我理解应该总是这样:

class Device < ActiveRecord::Base
  belongs_to :user
  validates_uniqueness_of :token
end

但是,我已经开始看到令牌唯一性的验证错误:

ActiveRecord::RecordInvalid: Validation failed: Token has already been taken

psql 中的手动查询确认设备正在尝试使用已在不同用户下的表中的令牌进行注册。这不应该是不可能的吗?我转换令牌的方式是否会截断它们?我检查了问题第一次出现时我能找到的每个代码示例,每个人似乎都使用我在第一个代码示例中列出的方法。

4

3 回答 3

7

如果有人注销然后使用其他帐户登录,则设备可能会尝试使用其他用户下的表中已有的令牌进行注册。

我会在服务器上为用户user和令牌字符串执行以下操作token(假设一次只能在一台设备上登录一个用户):

  1. 检查是否有Devicefor token_string
  2. 如果没有设备,则为token_string和创建一个user
  3. 如果存在设备而其用户不存在user,则将其用户更新为user.

这样,将为最后登录设备的用户发送推送通知。

关于NSData在设备上将 转换为十六进制字符串的方式,您不应依赖-[NSData description]. 最好以编程方式进行(输入,未测试):

- (NSString *)hexStringForData:(NSData *)data
{
    NSUInteger length = data.length;
    const char *bytes = data.bytes;
    NSMutableString *result = [NSMutableString stringWithCapacity:length * 2];
    for (int i = 0; i < length; i++) {
        [result appendFormat:@"%02x", bytes[i] & 0xff];
    }
    return [result copy];
}
于 2013-03-07T11:22:21.923 回答
1

我会赌这个猜测,但把它当作它的用途,猜测。

当 iOS 设备从备份中恢复时,或者当它们被“恢复”到新设备上时,例如,有人从 iPhone 4 升级到 iPhone 5,或者当有人将他们的 iPhone 给他们的妻子或在 eBay 上出售时,你会被复制/冗余/混淆设备数据。我确实看到了这种情况,但不是专门针对 APNS 令牌。

以下是APNS 文档对此的看法:

通过在每次启动应用程序时请求设备令牌并将其传递给提供者,您可以帮助确保提供者拥有设备的当前令牌。如果用户将备份恢复到为其创建备份的设备或计算机之外的设备或计算机(例如,用户将数据迁移到新设备或计算机),他或她必须至少启动一次应用程序以使其恢复再次收到通知。如果用户将备份数据恢复到新设备或计算机,或重新安装操作系统,则设备令牌会更改。此外,永远不要缓存设备令牌并将其提供给您的提供商;始终在需要时从系统获取令牌。如果您的应用程序之前已注册,请调用 registerForRemoteNotificationTypes:

因此,我没有查看您的代码,但您的“重复”令牌似乎与不每次都注册、某种缓存和设备恢复的某种组合有关。

于 2013-03-06T13:08:41.623 回答
0

了解设备注册时会发生什么很重要。它会向您的服务器发送关于以下内容的 POST:

/passkit/v1/devices/<deviceID>/registrations/<typeID>/<serial#>

在 JSON 有效负载中是push_token. 重要的是deviceIDpush_token。就 Apple 而言,您通过 Apple 的系统与设备进行通信,仅此push_token而已。

至于deviceID,它是实际使用的物理设备。设备可能想要多次注册的事实无关紧要,您的代码应该push_token根据最新的注册尝试简单地更新数据库中的内容。就是这样。

于 2013-03-09T09:50:11.593 回答