分类 iOS 下的文章

本地推送

发送通知

//
//  ViewController.swift
//  01-通知
//
//  Created by admin on 16/5/4.
//  Copyright © 2016年 snsnb. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }
    @IBAction func addLocalNotification(sender: UIButton) {

        /**
         // 消息发出的时间
         @NSCopying public var fireDate: NSDate?
         // 时区
         @NSCopying public var timeZone: NSTimeZone?
         // 通知周期
         public var repeatInterval: NSCalendarUnit // 0 means don't repeat
         @NSCopying public var repeatCalendar: NSCalendar?

         // location-based scheduling

         // 区域
         @available(iOS 8.0, *)
         @NSCopying public var region: CLRegion?

         // when YES, the notification will only fire one time. when NO, the notification will fire every time the region is entered or exited (depending upon the CLRegion object's configuration). default is YES.
         @available(iOS 8.0, *)
         public var regionTriggersOnce: Bool

         // 通知内容
         public var alertBody: String? // defaults to nil. pass a string or localized string key to show an alert
         // 是否显示 alertAction 设置的内容
         public var hasAction: Bool // defaults to YES. pass NO to hide launching button/slider
         // 设置提醒文字
         public var alertAction: String? // used in UIAlert button or 'slide to unlock...' slider in place of unlock
         // 设置从提醒进入app时的启动图片
         public var alertLaunchImage: String? // used as the launch image (UILaunchImageFile) when launch button is tapped
         @available(iOS 8.2, *)
         // 设置标题
         public var alertTitle: String? // defaults to nil. pass a string or localized string key

         // 声效
         public var soundName: String? // name of resource in app's bundle to play or UILocalNotificationDefaultSoundName

         // 数字
         public var applicationIconBadgeNumber: Int // 0 means no change. defaults to 0

         //
         public var userInfo: [NSObject : AnyObject]? // throws if contains non-property list types

         // category identifer of the local notification, as set on a UIUserNotificationCategory and passed to +[UIUserNotificationSettings settingsForTypes:categories:]
         @available(iOS 8.0, *)
         public var category: String?
        */
        // 创建通知
        var localNotification = UILocalNotification()

        // 设置时间
        localNotification.fireDate = NSDate(timeIntervalSinceNow: 5)

        // 设置消息内容
        localNotification.alertBody = "哈哈哈,我是内容"
        // 设置消息标题
        if #available(iOS 8.2, *) {
            localNotification.alertTitle = "我是标题"
        } else {
            // Fallback on earlier versions
        }
        // 设置 alertAction
        localNotification.alertAction = "快点打开"
        // 设置 alertAction 是否显示,默认为显示
        localNotification.hasAction = false
        // 声效
        localNotification.soundName = UILocalNotificationDefaultSoundName
        // 图标数字
        localNotification.applicationIconBadgeNumber = 888
        // 传递自定义的信息
        localNotification.userInfo = ["body":localNotification.alertBody!,"badgeNumber":888]
        // 推送通知
        UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
    }
}

获取通知传递的值

//
//  AppDelegate.swift
//  01-通知
//
//  Created by admin on 16/5/4.
//  Copyright © 2016年 snsnb. All rights reserved.
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        /**
         public static var None: UIUserNotificationType { get } // the application may not present any UI upon a notification being received
         public static var Badge: UIUserNotificationType { get } // the application may badge its icon upon a notification being received
         public static var Sound: UIUserNotificationType { get } // the application may play a sound upon a notification being received
         public static var Alert: UIUserNotificationType { get } // the application may display an alert upon a notification being received

        */
        // ios8 之后需要授权
        if #available(iOS 8.0, *) {
            let notificationSettings = UIUserNotificationSettings(forTypes: [UIUserNotificationType.Alert,UIUserNotificationType.Sound,UIUserNotificationType.Badge], categories: nil)
            application.registerUserNotificationSettings(notificationSettings)
        }
        application.applicationIconBadgeNumber = 0
        // 只要是不是正常从图标点击进入的就会进入这个if
        if launchOptions != nil
        {
            // 注意,
            // print("通知进入")
            let view = UILabel(frame: CGRectMake(0, 120, UIScreen.mainScreen().bounds.size.width, UIScreen.mainScreen().bounds.size.height - 120))
            view.backgroundColor = UIColor.darkGrayColor()
            view.numberOfLines = 0
            // 因为不能打印,所以在控件里面显示来查看效果
            // view.text = "\(launchOptions)"
            // view.text = "\(launchOptions![UIApplicationLaunchOptionsLocalNotificationKey])"
            // 可以取到传递的内容了,需要先转换下
            let notification = launchOptions![UIApplicationLaunchOptionsLocalNotificationKey] as! UILocalNotification;
            view.text = "\(notification.userInfo)"
            self.window?.rootViewController?.view.addSubview(view)
        }
        return true
    }
    // 从通知进入 app 的时候做相应的处理,在这里面进行处理的话,当程序被杀死的之后,再从通知进入应用,是无效的
    func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
        // 当应用处于活动状态时,直接 return ,后面就可以做相关的操作
        if application.applicationState == UIApplicationState.Active {
            return
        }
        // 当应用处于正在进入活动状态时,执行相应的操作
        if application.applicationState == UIApplicationState.Inactive {
            // print("跳转")
            // print(notification.userInfo)
        }
    }
}

远程推送

//
//  AppDelegate.swift
//  远程推送
//
//  Created by admin on 16/5/5.
//  Copyright © 2016年 snsnb. All rights reserved.
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        // 8.0 之后需要授权
        if #available(iOS 8.0, *) {
            // 初始化设置对象
            let setting = UIUserNotificationSettings(forTypes: [UIUserNotificationType.Badge,UIUserNotificationType.Sound,UIUserNotificationType.Alert], categories: nil)
            // 注册
            application.registerUserNotificationSettings(setting)
            // 注册远程通知
            application.registerForRemoteNotifications()
        } else {
            UIApplication.sharedApplication().registerForRemoteNotificationTypes([UIRemoteNotificationType.Badge,UIRemoteNotificationType.Sound,UIRemoteNotificationType.Alert])
        }
        // 和本地消息一样,在程序被杀死的状态下,也需要在这里获取下传递来的消息
        if launchOptions != nil {
            let lableRect = UIScreen.mainScreen().bounds
            let lable = UILabel(frame: lableRect)
            lable.numberOfLines = 0
            lable.backgroundColor = UIColor.grayColor()
            // 全部信息
            // lable.text = "\(launchOptions)"
            // 传递来的消息
            lable.text = "\(launchOptions![UIApplicationLaunchOptionsRemoteNotificationKey])"
            self.window?.rootViewController?.view.addSubview(lable)
        }
        return true
    }
    // 获得设备标识,把标识纪录下,在给apple服务器发送的时候需要用到
    func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData)
    {
        print(deviceToken.description)
    }
    // 获得传递的消息
    func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject])
    {
        // 可以打印消息
        print(userInfo)
    }
}

php发送apple远程推送

参考网址:http://wenku.baidu.com/link?url=92uLZLWTQcTJ-ZY9GgwNz8LlLEVP67pdnkP8VJnQrbJhnP7LAGhCbEydVxUkYLmGQdVCFLExG-yuHLjIdkA-S_DPcI-HFUvARK4dX3up36O
还有几个网址,浏览器关了,找不到了,就不贴了
配置证书就不记录了,纪录下证书转换成php能处理的格式的步骤。注意以下步骤有几个需要输入密码的地方,分别有不同的用途,为了避免之后混淆,我都设置成一样了

#推送证书转换,这个是从apple下载的推送证书
openssl x509 -in aps_development.cer -inform der -out PushChatCert.pem
#导出的p12证书转换,注意这个p12证书是从推送证书导出的p12文件
openssl pkcs12 -nocerts -out PushChatKey.pem -in Push.p12
#合并
cat PushChatCert.pem PushChatKey.pem > ck.pem
#测试是否能连接苹果的服务器
telnet gateway.sandbox.push.apple.com 2195

测试是否能连接苹果的服务器

telnet gateway.sandbox.push.apple.com 2195

出现以下即ok,可以继续进行下面的步骤

admindeMac-mini:远程推送 admin$ telnet gateway.sandbox.push.apple.com 2195
Trying 17.172.232.18...
Connected to gateway.sandbox.push-apple.com.akadns.net.
Escape character is '^]'.

查看证书是否有效,注意在执行下面命令的时候会输入密码,就是之前设置的密码

openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushChatCert.pem -key PushChatKey.pem

出现以下结果即ok,可以进行后续的

#省略一部分。。。
SSL handshake has read 3160 bytes and written 2153 bytes
---
New, TLSv1/SSLv3, Cipher is AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : AES256-SHA
    Session-ID: 
    Session-ID-ctx: 
    Master-Key: B10518ED571EFFF74E16A6C4BF0D61CC4ECA21AED726C01D110B8B879A190F9300578F1D764513AB29C2D11174F8395A
    Key-Arg   : None
    Start Time: 1462440274
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
#省略一部分。。。

php代码

<?php
/**
 * Created by PhpStorm.
 * User: admin
 * Date: 16/5/5
 * Time: 下午2:37
 */

error_reporting(E_ALL);
ini_set('display_errors', '1');

//将出错信息输出到一个文本文件
ini_set('error_log', dirname(__FILE__) . '/error_log.txt');

//手机注册应用返回唯一的deviceToken
$deviceToken = '20596a98 b837fbe3 3df0f3f6 017bfb7e f96fc863 0dc11d0b 926f05dc c3c0b95f';//隐藏了自己的token
// 在google上搜索的时候,有的人因为写的不是绝对路径,或者文件不在本机而导致推送失败的,所以这里最好写本机的绝对路径
$pem = dirname(__FILE__) .'/'.'ck.pem';
//ck.pem通关密码
$pass = '123456';
//消息内容
$message = 'A test message!';
//badge我也不知是什么
$badge = 88;
//推送消息到手机时的提示音类型
$sound = 'default';
//建设的通知有效载荷(即通知包含的一些信息)
$body = array();
$body['aps'] = array('alert' => $message);// 弹窗显示的消息
$body['aps']['sound'] = $sound;// 声音
$body['aps']['badge'] = $badge;// 图标数字
//把数组数据转换为json数据
$payload = json_encode($body);
echo strlen($payload),"\r\n";

//下边的写法就是死写法了,一般不需要修改,
//唯一要修改的就是:ssl://gateway.sandbox.push.apple.com:2195这个是沙盒测试地址,ssl://gateway.push.apple.com:2195正式发布地址
$ctx = stream_context_create();

stream_context_set_option($ctx, 'ssl', 'local_cert', $pem);
stream_context_set_option($ctx, 'ssl', 'passphrase', $pass);
/** 
 * 有人不能推送是 要加上这个
 * stream_context_set_option($ctx, 'ssl', 'cafile', 'entrust_2048_ca.cer'); 
 * 这个cer需要下载,但是有这个选项的话在生成 pem 文件的时候就和上面不一样了,因为没有遭遇到这样的错误,就不尝试了
 */
// ssl 和 tls 都可以
$fp = stream_socket_client('tls://gateway.sandbox.push.apple.com:2195',$err,$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp) {
    print "Failed to connect $err $errstr\n";
    return;
}
else {
    print "Connection OK\n<br/>";
}
// send message
$msg = chr(0) . pack("n",32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n",strlen($payload)) . $payload;
print "Sending message :" . $payload . "\n";
fwrite($fp, $msg);
fclose($fp);
/*
35 Connection OK
Sending message :{"aps":{"alert":"A test message!"}} 
*/