美文网首页PHP开发
iOS10推送(APNS)App+后端实现

iOS10推送(APNS)App+后端实现

作者: tomfriwel | 来源:发表于2021-10-26 16:47 被阅读0次

Xcode里的相关配置如下:


Capability设置

APP实现

获取Device Token和处理通知,直接贴代码:

AppDelegate.h:

#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import <UserNotifications/UserNotifications.h>
#endif

@interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate>

@property (nonatomic, strong) UIWindow *window;

@end

AppDelegate.m:

#import "AppDelegate.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
    //iOS10特有
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    // 必须写代理,不然无法监听通知的接收与点击
    center.delegate = self;
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
      if (granted) {
        // 点击允许
        NSLog(@"注册成功");
        [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
          NSLog(@"%@", settings);
        }];
      } else {
        // 点击不允许
        NSLog(@"注册失败");
      }
    }];
  }
  // 注册获得device Token
  [[UIApplication sharedApplication] registerForRemoteNotifications];
  return YES;
}

#pragma mark - RemoteNotifications
// 获得Device Token
 - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
   const unsigned *tokenBytes = [deviceToken bytes];
   NSString *hexToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                            ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                            ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                            ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
   NSLog(@"DeviceToken: %@", hexToken);
//   [[MyModel sharedModel] setApnsToken:hexToken];
}
// 获得Device Token失败
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error);
}


#pragma mark - UNUserNotificationCenterDelegate

// iOS 10收到通知
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
    NSDictionary * userInfo = notification.request.content.userInfo;
    UNNotificationRequest *request = notification.request; // 收到推送的请求
    UNNotificationContent *content = request.content; // 收到推送的消息内容
    NSNumber *badge = content.badge;  // 推送消息的角标
    NSString *body = content.body;    // 推送消息体
    UNNotificationSound *sound = content.sound;  // 推送消息的声音
    NSString *subtitle = content.subtitle;  // 推送消息的副标题
    NSString *title = content.title;  // 推送消息的标题
    
    if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
      NSLog(@"iOS10 前台收到远程通知:%@", notification);
//      NSLog(@"iOS10 前台收到远程通知:%@", [self logDic:userInfo]);
    } else {
        // 判断为本地通知
        NSLog(@"iOS10 前台收到本地通知:{\\\\nbody:%@,\\\\ntitle:%@,\\\\nsubtitle:%@,\\\\nbadge:%@,\\\\nsound:%@,\\\\nuserInfo:%@\\\\n}",body,title,subtitle,badge,sound,userInfo);
    }
    completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert); // 需要执行这个方法,选择是否提醒用户,有Badge、Sound、Alert三种类型可以设置
}

// 通知的点击事件
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler{
    NSDictionary * userInfo = response.notification.request.content.userInfo;
    UNNotificationRequest *request = response.notification.request; // 收到推送的请求
    UNNotificationContent *content = request.content; // 收到推送的消息内容
    NSNumber *badge = content.badge;  // 推送消息的角标
    NSString *body = content.body;    // 推送消息体
    UNNotificationSound *sound = content.sound;  // 推送消息的声音
    NSString *subtitle = content.subtitle;  // 推送消息的副标题
    NSString *title = content.title;  // 推送消息的标题
    if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        NSLog(@"iOS10 收到远程通知:%@", response);
//      NSLog(@"iOS10 收到远程通知:%@", [self logDic:userInfo]);
    }
    else {
        // 判断为本地通知
        NSLog(@"iOS10 收到本地通知:{\\\\nbody:%@,\\\\ntitle:%@,\\\\nsubtitle:%@,\\\\nbadge:%@,\\\\nsound:%@,\\\\nuserInfo:%@\\\\n}",body,title,subtitle,badge,sound,userInfo);
    }
    
    // Warning: UNUserNotificationCenter delegate received call to -userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: but the completion handler was never called.
    completionHandler();  // 系统要求执行这个方法

}

@end

这里的hexTokenDevice Token)是需要记录的,传到后端存起来。处理这个token的时候需要注意,重新安装App后其值发生变化,后端存储的时候要考虑到这种情况。比如更新用户的token信息。

如果不开发后端,想直接测试推送的话,可以使用SmartPush模拟推送,进行测试。里面涉及到一个证书的配置,可以看这篇文章:手把手教你实现iOS 远程推送

后端(PHP,框架CodeIgniter)

token-basedcertificate-based两种方式发送请求。

我这里用的是token-based,这种方式需要以下几个信息:

  1. Key(后缀名是.p8)文件和对应的Key ID
  2. Team ID
  3. App的Bundle ID
  4. Device Token(App里获取,见上文)

1. 创建Key

创建Key
输入Key Name并选择Apple Push Notifications service后 ,点击右上角Continue
点击右上角Register
下载Key文件(只能下一次,妥善保存),记录Key ID

2. Team ID

获取Team ID

后端代码

拿到这些信息后,就可以发送推送请求了。
把下载下来的Key(后缀名是.p8)文件上传到服务器上。

几个重要信息可以存储在其它地方,这里只是为了方便。

define('AUTH_KEY_PATH', '<path-to-p8-file>');
define('AUTH_KEY_ID', '<Key ID for your p8>');
define('TEAM_ID', '<your team id>');
define('BUNDLE_ID', '<your app bundle identifier>');

private function generateAuthenticationHeader() {
  $header = base64_encode(json_encode([
                'alg' => 'ES256',
                'kid' => AUTH_KEY_ID
            ]));

  $claims = base64_encode(json_encode([
                'iss' => TEAM_ID,
                'iat' => time()
            ]));

  $pkey = openssl_pkey_get_private('file://' . AUTH_KEY_PATH);
  openssl_sign("$header.$claims", $signature, $pkey, 'sha256');

  $signed = base64_encode($signature);
  return "$header.$claims.$signed";
}

private function sendNotification($debug, $token, $payload) {
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
      'apns-topic: ' . BUNDLE_ID,
      'authorization: bearer ' . $this->generateAuthenticationHeader(),
      'apns-push-type: alert'
  ]);

// 如果正式环境,$debug=false,不然下面$response会出现BadDeviceToken的错误
  $server = $debug ? 'api.development' : 'api';
  $url = 'https://'.$server.'.push.apple.com/3/device/'.$token;
  curl_setopt($ch, CURLOPT_URL, $url);
  
  $response = curl_exec($ch);
  
  if ($response === false) {
      return ["curl_exec failed: " . curl_error($ch)];
  }
  
  $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  if ($code === 400 || $code === 410) {
      $json = @json_decode($response);
      return ['Reason: '.$json->reason, $code];
      // if ($json->reason === 'BadDeviceToken') {
      //   //  echo 'BadDeviceToken';
      // }
  }
  
  curl_close($ch);
  return [$response, $code];
}

public function testpush() {
  $deviceToken = '<your device token>';
  $payload = [
    "aps"=>[
      "alert"=>[
        "title"=>"Game Request",
        "body"=>"Bob wants to play poker",
      ],
      "badge"=>1,
    ],
  ];
  $result = $this->sendNotification(true, $deviceToken, $payload);
  echo json_encode($result);
}

payload的具体设置可见 Creating the Remote Notification Payload

相关参考

相关文章

  • iOS10推送(APNS)App+后端实现

    Xcode里的相关配置如下: APP实现 获取Device Token和处理通知,直接贴代码: AppDelega...

  • iOS10 - 推送通知

    iOS10里的通知与推送 通知文章2 远程推送工具 一、各版本通知比较 iOS 8以后,APNs推送的字节是2k,...

  • nodejs APNS

    node-apnnodejs + apn 推送给apns服务器的问题用NODEJS实现APNS

  • 生成APNs后端推送证书

    一. 获取SSL连接证书: 在Apple Developer官网,打开App IDs列表,找到app对应的APP ...

  • iOS推送记录

    APNSiOS端代码实现 APNS推送工具 推送工具: https://github.com/shaojianku...

  • iOS怎么推送统计到达率

    掘金地址github地址 ios摘要 iOS10里的通知与推送 国内 90%以上的 iOS 开发者,对 APNs ...

  • APNS消息推送的实现(完整步骤)

    1. 原理及代码实现 iOS远程推送原理及实现过程 苹果远程推送通知 APNs 详解,官方,iOS | Swift...

  • iOS远程推送(Objective-C & Swift)

    iOS远程推送 APNS远程推送的流程: 1、app 注册到 APNS。2、APNS 下发 devicetoken...

  • 本地推送闹钟功能实现

    本地推送闹钟功能实现 在ios10下使用UserNotifications用本地推送实现闹钟功能,只是实现了简单的...

  • iOS APNS

    APNS推送机制 APNS注意事项 1、APNS免费,但需要开发者账号2、APNS不稳定,Apple对消息推送的可...

网友评论

    本文标题:iOS10推送(APNS)App+后端实现

    本文链接:https://www.haomeiwen.com/subject/ebtyaltx.html