在iOS 8中获取设备令牌

18

我需要设备令牌来实现我的应用程序中的推送通知。
由于在iOS 8上,didRegisterForRemoteNotificationsWithDeviceToken方法无效,所以我该如何获取设备令牌? 我在应用委托中尝试了这段代码,但它没有给我设备令牌。

    [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
    [[UIApplication sharedApplication] registerForRemoteNotifications];

你可以在iOS 8文档中轻松找到这个:UIUserNotificationSettings - rckoenes
我已经注册了UIUserNotificationSettings,但它如何提供设备令牌给我呢? - Pankaj
1
你实现了 application:didRegisterUserNotificationSettings: 吗?文档里有提到! - rckoenes
8个回答

56

阅读UIApplication.h中的代码。

你就会知道如何做了。

首先:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

添加类似这样的代码

#ifdef __IPHONE_8_0
  //Right, that is the point
    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIRemoteNotificationTypeBadge
|UIRemoteNotificationTypeSound
|UIRemoteNotificationTypeAlert) categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
#else
    //register to receive notifications
    UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:myTypes];
#endif

如果您没有同时使用Xcode 5和Xcode 6,请尝试使用此代码

if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
  UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIRemoteNotificationTypeBadge
      |UIRemoteNotificationTypeSound
      |UIRemoteNotificationTypeAlert) categories:nil];
  [application registerUserNotificationSettings:settings];
} else {
  UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
  [application registerForRemoteNotificationTypes:myTypes];
}

(感谢@zeiteisen和@dmur的提醒)


第二步:

添加此功能

#ifdef __IPHONE_8_0
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
    //register to receive notifications
    [application registerForRemoteNotifications];
}

- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler
{
    //handle the actions
    if ([identifier isEqualToString:@"declineAction"]){
    }
    else if ([identifier isEqualToString:@"answerAction"]){
    }
}
#endif

你可以在此处获得设备令牌

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

如果还是不起作用,使用此函数并记录错误日志。

-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error

谢谢你的回答。我会检查一下并告诉你。 - Pankaj
谢谢,这对我有用,但是应该是UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert而不是UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert,对吗? - Juan de la Torre
10
这将在iOS 8以下的版本上崩溃。 #ifdef是一个编译器函数,会在编译时进行评估。你仍然需要运行时检查! - Dan VanWinkle
2
你可以在方法内使用 if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0 && [[[UIDevice currentDevice] systemVersion] floatValue] < 9.0)) - cannyboy
2
我尝试了这个,但是在iOS 8上,(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken没有被调用,原因不明。(至少我的所有命令,包括NSLog都没有执行。)有可能的解决方案吗? - John
显示剩余2条评论

11

如果你的应用在旧版iOS上崩溃,可以在 @Madao 的回答中添加一些小的验证:

#ifdef __IPHONE_8_0
if(NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1) {
    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert) categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
}
#endif

UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound |     UIRemoteNotificationTypeNewsstandContentAvailability;
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:myTypes];

__IPHONE_8_0宏的作用是允许您在旧版本的xCode/iOS中进行编译,这样您就不会收到编译错误或警告,但在运行代码时,iOS 7或更低版本的设备会导致崩溃。


这正是我打算在Madao的帖子下评论的内容。 - Dan VanWinkle
2
我做了这个并且它有效,如果([application respondsToSelector:@selector(registerUserNotificationSettings:)]) { UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil]; [application registerUserNotificationSettings:settings]; } else { [application registerForRemoteNotificationTypes: UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound]; } - zumzum

3
在iOS8及以上版本中获取设备令牌的方法:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//This code will work in iOS 8.0 xcode 6.0 or later
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
{
    [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
    [[UIApplication sharedApplication] registerForRemoteNotifications];
}
else
{
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeNewsstandContentAvailability| UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
}
return YES;
}

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
NSString* deviceToken = [[[[deviceToken description]
                         stringByReplacingOccurrencesOfString: @"<" withString: @""]
                         stringByReplacingOccurrencesOfString: @">" withString: @""]
                         stringByReplacingOccurrencesOfString: @" " withString: @""] ;
NSLog(@"Device_Token     -----> %@\n",deviceToken);
}

1

2020解决方案

六个步骤,

1. 图书馆

enter image description here

2. 将代码添加到AppDelegate中

// APNs:

func application(_ application: UIApplication,
      didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    print(">> getting an APNs token works >>\(deviceToken)<<")
    let tokenAsText = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
}

func application(_ application: UIApplication,
      didFailToRegisterForRemoteNotificationsWithError error: Error) {
    print(">> error getting APNs token  >>\(error)<<")
}

3. 在您的应用程序中

例如,在用户登录后

import UserNotifications

并且

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    askNotifications()
}

func askNotifications() {
    let n = UNUserNotificationCenter.current()
    n.requestAuthorization(options: [.alert, .sound, .badge]) {
        granted, error in
        print("result \(granted) \(String(describing: error))")

        guard granted else {
            print("not granted!")
            return
        }

        DispatchQueue.main.async {
            UIApplication.shared.registerForRemoteNotifications()
        }
    }
}

4. 能力选项卡

三个项目

enter image description here

注意旧文章:现在没有“开关”了。

5. 手机连接,无模拟器

它将不会在模拟器中工作。必须是手机。

enter image description here

手机连接电脑后是可以的,控制台也可以正常工作。

6. 最后... WIFI 舞蹈

从2020年开始,您必须按照以下步骤操作才能保证100%的重复性:

  1. 从手机上完全擦除应用程序
  2. 构建到手机并从Xcode运行 (它绝对不会起作用)
  3. 强制退出应用程序
  4. 从手机上完全擦除应用程序
  5. 关闭wifi / 移动数据
  6. 从Xcode构建到手机并运行 (显然它不会起作用)
  7. 强制退出应用程序

然后按照以下顺序:

  1. 从手机上完全擦除应用程序
  2. 打开连接(无论是wifi还是移动数据都可以-没有问题)
  3. 从Xcode构建到手机并运行

现在它可以工作了。(并且从此以后都可以工作。)

WIFI DANCE只是苹果的一种奇怪现象。他们还没有修复它(Xcode 11.3)。事实上,它已经变成了“100%可重复”的:您必须执行WIFI DANCE。


0

这是解决方案。

在applicationDidFinishLaunchingWithOptions中:

{

 UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
    UIUserNotificationSettings *mySettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:mySettings];
}


- (void)application:(UIApplication*)application didRegisterUserNotificationSettings:(nonnull UIUserNotificationSettings *)notificationSettings
{
    [application registerForRemoteNotifications];
}


- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(nonnull NSError *)error
{
    NSLog(@" Error while registering for remote notifications: %@", error);
}

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(nonnull NSData *)deviceToken
{
  NSLog(@"Device Token is : %@", deviceToken);
}

0

@madoa的答案完全正确。 只需注意在模拟器中无法正常工作

在这种情况下

-(void)application:(UIApplication *)application
     didFailToRegisterForRemoteNotificationsWithError:(NSError *)error

出现错误REMOTE_NOTIFICATION_SIMULATOR_NOT_SUPPORTED_NSERROR。


0

除了其他傲慢的回答之外,对于一个已经实现了所有必需委托方法的知情开发人员来说,这个问题可能出现的最有可能的原因是他们正在使用通配符配置文件(为什么不呢?这样可以轻松创建和测试开发应用程序!)

在这种情况下,您可能会看到错误Error Domain=NSCocoaErrorDomain Code=3000 "no valid 'aps-environment' entitlement string found for application"

为了测试通知,您实际上必须回到2000年以后,登录developer.apple.com,并设置启用推送通知的特定于应用程序的配置文件。

  1. 创建与您的应用程序包标识符相对应的应用程序ID。确保勾选“推送通知”(当前从底部开始的第二个选项)。
  2. 为该应用程序ID创建一个配置文件。
  3. 完成我们都希望忘记的其余可怕的配置步骤。
  4. 利润!

0

在您的开发者帐户中,请确保您已正确设置应用程序ID中的推送通知,然后需要重新生成并下载您的配置文件。我的问题是我已经下载了配置文件,但xcode正在运行不正确的配置文件。要解决此问题,请转到目标构建设置,向下滚动到代码签名,在配置文件部分下,确保您正在使用与您生成的名称匹配的正确配置文件(如果您安装了多个,则应该有一个下拉菜单选项)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接