集成极光推送、静态库、动态库


推送通知和NSNotification有区别


  • NSNotification是抽象的,不可见的
  • 推送通知是能用眼睛看到的

两种推送通知


  • 本地通知(Local Notification):手机应用本身的通知,比如:闹钟。就是用来提醒用户完成一些任务。
  • 特点:不需要联网就能发出推送通知(不需要服务器的支持)。
  • 远程(推送)通知(Remote Notification):远程服务器联网推送给客户端的通知,以下列出5个常见的远程通知。
  • 1.qq在后台,屏幕顶部出现横幅,横幅的内容是别人给你发的信息,但是一会就消失了,这个就是远程通知
  • 2.UIAlertView弹框提示也是远程通知
  • 3.锁屏状态下能收到别人给你发的信息也是远程通知
  • 4.下拉屏幕出现的通知选项也是远程通知
  • 5.图标右上角出现的1,2,3... 也是远程通知

本地通知和远程(推送)通知的区别


  • 本地通知的局限性:只要用户关闭了app,就无法跟app的服务器沟通,无法从服务器获得最新的数据内容

  • 远程通知的优越性:用户关闭了app,只要联网了,也能收到服务器推送的远程通知,能收到远程通知的原因就是建立了长连接

  • 远程(推送)通知必须知道的知识点:

  • 1.所有的苹果设备,在联网状态下,都会与苹果服务器建立长连接

  • 2.长连接:只要联网,就一直建立连接,不联网,就无法建立连接.

  • 3.长连接的作用:时间校准、系统升级、查找我的iPhone.

  • 4.长连接的好处:数据传输速度快、数据保持最新状态(实时更新).

  • Device Token = 手机的UDID + App的Bundle ID

  • 远程推送服务:APNS(Apple Push Notification Services)。

  • APNS和远程推送通知的关系

  • 远程推送通知要经过APNS才能推送到手机上。

  • device token,即设备令牌。根据自己的设备(UDID)和应用(Bundle ID)向APNS服务器发出请求来换取一个device token。

  • device token作用:如果应用需要发出通知给某个手机,但是应用发出的信息不是直接给手机的,而是必须统一交给APNS服务器。APNS服务器通过device token,知道应用要发的消息是给哪个手机设备的,并转发该消息给手机,手机再通知应用程序。


做远程(推送)通知的条件:


  • 如果是真机调试阶段(常用),需要如下准备:

    • 真机调试的证书
    • 远程推送通知的开发证书
    • Bundle ID
    • 真机设备
    • 根据上面4个生成的描述文件
  • 如果是发布阶段(不经常用),需要如下准备:

    • 发布阶段的证书
    • 远程推送通知的生产证书
    • Bundle ID
    • 真机设备
    • 根据上面4个生成的描述文件
  • 总结:

    • 类似真机调试\打包测试\发布的做法.只不过限制电脑时,真机调试阶段的话必须选择Apple Push Notification service SSL(Sandbox),发布阶段必须选择Apple Push Notification service SSL (Sandbox & Production)
    • 精华:看Idenfifiers-App IDs 选项的Development字段、Distribution字段下面是Enable还是Disabled,可以判断出这两个字段(开发阶段、发布阶段)的状态

真机调试+远程推送通知


1.创建请求文件(打开 keychain Access)把请求文件放到Certificates中安装,并下载一个cer后缀的证书

61-25.gif

2.登录开发者账号,生成真机调试阶段需要的证书+远程推送通知的开发证书+Bundle ID+真机设备+描述文件

61-26.gif
61-26-2.gif

3安装真机调试的证书+安装远程推送通知的开发证书+安装描述文件

61-27.gif

4.创建用于真机调试+远程推送通知阶段的xcode文件并在xcode中指定Bundle ID、描述文件、证书

61-28-1.gif
61-28-2.gif

5.在AppDelegate.m文件中写代码完成远程推送通知

61-29.gif

6.利用PushMeBaby作为服务器,让真机拿到通知的内容显示在真机设备上

61-30.gif

相关代码

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    if ([UIDevice currentDevice].systemVersion.doubleValue <= 8.0) {
        // 不是iOS8
        UIRemoteNotificationType type = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert;
        // 当用户第一次启动程序时就获取deviceToke
        // 该方法在iOS8以及过期了
        // 只要调用该方法, 系统就会自动发送UDID和当前程序的Bunle ID到苹果的APNs服务器
        [application registerForRemoteNotificationTypes:type];
    }else
    {
        // iOS8
        UIUserNotificationType type = UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound;
        
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:type categories:nil];
        // 注册通知类型
        [application registerUserNotificationSettings:settings];
        
        // 申请试用通知
        [application registerForRemoteNotifications];
    }
    return YES;
}

/**
 *  获取到用户对应当前应用程序的deviceToken时就会调用
 */
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    NSLog(@"%@", deviceToken);
}
@end



利用极光实现##真机调试+远程推送通知


1.创建请求文件(打开 keychain Access)把请求文件放到Certificates中安装,并下载一个cer后缀的证书
61-31.gif
2.登录开发者账号,生成真机调试阶段需要的证书+远程推送通知的开发证书+远程推送通知的生产证书+Bundle ID+真机设备+描述文件
61-32.gif
3.安装真机调试的证书+安装远程推送通知的开发证书+安装远程推送通知的发展证书+安装描述文件+搭导出远程推送通知的开发证书的p12文件+导出远程推送通知的发展证书的p12文件
61-33.gif
4.登录https://www.jiguang.cn+创建应用(加载步骤3导出的两个p12文件)
61-34.gif
5.创建用于真机调试+远程推送通知阶段的xcode文件并在xcode中指定Bundle ID、描述文件、证书
61-35.gif
6.下载极光的iOS SDK+查看极光的iOS SDK集成指南,按照集成指南来集成极光的iOS SDK
61-36.gif
7.打开Xcode中的后台模式+开启手机的Wifi+运行添加到AppDelegate.m中的代码
61-37.gif
8.打开极光,找到"发送通知"按钮,填写通知的内容,点击立即发送,手机进入后台,即可收到通知
61-38.gif

获得Device Token时提示如下问题的解决办法


问题1:
You've implemented -[ application:didReceiveRemoteNotification:fetchCompletionHandler:], but you still need to add "remote-notification" to the list of your supported UIBackgroundModes in your Info.plist.
问题1的解决办法
集成极光推送、静态库、动态库_第1张图片
99-01.png

问题2:
Not get deviceToken yet. Maybe: your certificate not configured APNs
```
#####解决办法:手机联wifi即可解决问题
---
#####问题3:
```
Use of undeclared identifier 'ASIdentifierManager'
```
#####解决办法1:
```
导入#import 文件即可解决问题
```
#####解决办法2:
```
删除NSString *advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];代码
```
---
#####问题4:
```
 /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.60.12/UIApplication.m:3401
```
#####解决办法:
```
删除AppDelegate.m文件中的
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];

```

---

#远程推送通知具体流程
---
![61-31.png](http://upload-images.jianshu.io/upload_images/2364940-163c1f70d2be6122.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

---

![61-32.png](http://upload-images.jianshu.io/upload_images/2364940-98b3f1b02fd63cee.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

---

- 推送通知的调试阶段的证书+推送通知的发布阶段的证书+普通调试阶段的证书+描述文件+Bundle ID(开启通知功能)+真机设备=既可以实现真调试,也可以实现推送通知

- .a文件就是静态库,本质是.m文件,只不过将.m文件加密了,生成了.a文件

---
#本地通知
---

AppDelegate.m文件

```
#import "AppDelegate.h"

@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 注意: 在iOS8中, 必须提前注册通知类型
    if ([UIDevice currentDevice].systemVersion.doubleValue >= 8.0) {
        UIUserNotificationType type = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:type categories:nil];
        // 注册通知类型
        [application registerUserNotificationSettings:settings];
    }
    return YES;
    
}
// 代理方法:接收到本地通知时就会调用.程序必须在前台/后台,如果程序完全退出则不调用
// 当程序在前台时, 会自动调用该方法
// 当程序在后台时, 只有用户点击了提示的通知才会调用
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
    NSLog(@"%s", __func__);
    
    // 点击"注册通知"按钮,5秒后将会显示灰色的UILabel,与此同时,通知的内容也会一同显示在灰色的UILabel上
    static int count = 0;
    count++;
    UILabel *label = [[UILabel alloc] init];
    label.frame = CGRectMake(self.window.frame.size.width/2-100, 300, 200, 200);
    label.numberOfLines = 0;
    label.textColor = [UIColor whiteColor];
    label.text = [NSString stringWithFormat:@" %@", notification.userInfo];
    label.font = [UIFont systemFontOfSize:21];
    label.backgroundColor = [UIColor grayColor];
    [self.window.rootViewController.view addSubview:label];
}

@end
```

ViewController.m文件
```
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

}

/*
 @property(nonatomic,copy) NSDate *fireDate; 指定通知发送的时间
 @property(nonatomic,copy) NSTimeZone *timeZone; 指定发送通知的时区
 
 @property(nonatomic) NSCalendarUnit repeatInterval;  重复的周期, 枚举
 @property(nonatomic,copy) NSCalendar *repeatCalendar; 重复的周期  , 2014.12.12
 @property(nonatomic,copy) NSString *alertBody;      通知内容
 @property(nonatomic) BOOL hasAction;                是否需要华东事件
 @property(nonatomic,copy) NSString *alertAction;    锁屏状态的标题
 @property(nonatomic,copy) NSString *alertLaunchImage;   点击通知之后的启动图片
 @property(nonatomic,copy) NSString *soundName;    收到通知播放的音乐
 @property(nonatomic) NSInteger applicationIconBadgeNumber;  图标提醒数字
 @property(nonatomic,copy) NSDictionary *userInfo;   额外的信息
 */

#warning 验证程序的四大功能 
#warning 功能1:点击"注册通知"按钮,等5秒看屏幕文字的变化.
#warning 功能2:点击"注册通知"按钮,立刻将程序进入后台,然后点击收到的通知进入程序,看屏幕文字的变化 .
#warning 功能3:点击"注册通知"按钮,立刻将程序关闭,然后点击收到的通知进入程序,看屏幕文字的变化。
#warning 功能4:点击"注册通知"按钮,然后立刻按住Command+L锁屏,然后再次按住Command+L看到滑动解锁的字样,此时你看锁屏界面的变化。

- (IBAction)AddNotification:(UIButton *)sender{
    NSLog(@"%s", __func__);
    // 1.创建本地通知对象
    UILocalNotification *note = [[UILocalNotification alloc] init];
    
    // 指定通知发送的时间(指定5秒之后发送通知,didReceiveLocalNotification代理方法5秒后才调用)
    note.fireDate = [NSDate dateWithTimeIntervalSinceNow:10];
    // 注意: 在真实开发中一般情况下还需要指定时区(让通知的时间跟随当前时区)
    note.timeZone = [NSTimeZone defaultTimeZone];
    // 指定通知内容
    note.alertBody = @"Hello,我是通知的内容";
    
    // 设置通知重复的周期(1分钟通知一期)
    //    note.repeatInterval = NSCalendarUnitSecond;
    
    // 指定锁屏界面的信息(Command+L)
    note.alertAction = @"Hello,我是锁屏界面的信息";
    
    // 设置点击通知进入程序时候的启动图片
    note.alertLaunchImage = @"Default";
    
    // 收到通知播放的音乐
    note.soundName = @"m_07.wav";
    
    // 设置应用程序的提醒图标
    note.applicationIconBadgeNumber = 345;
    
    // 注册通知时可以指定将来点击通知之后需要传递的数据
    note.userInfo = @{@"name":@"zb",
                      @"age":@"25",
                      @"phone": @"13324233321"};
    
    // 2.注册通知(图片的名称建议使用应用程序启动的图片名称)
    UIApplication *app =  [UIApplication sharedApplication];
    // 每次调用添加方法都会将通知添加到scheduledLocalNotifications数组中
    [app scheduleLocalNotification:note];
    
}
- (IBAction)CancelNotification:(UIButton *)sender {
    UIApplication *app =  [UIApplication sharedApplication];
    // 清空通知
    [app cancelAllLocalNotifications];
    
}

@end
```
截图


![100.90.gif](http://upload-images.jianshu.io/upload_images/2364940-a4e7a5b4aff703ac.gif?imageMogr2/auto-orient/strip)



![100.91.gif](http://upload-images.jianshu.io/upload_images/2364940-a15d34a4e24871b3.gif?imageMogr2/auto-orient/strip)



![100.92.gif](http://upload-images.jianshu.io/upload_images/2364940-8c660d72798ce7fb.gif?imageMogr2/auto-orient/strip)




![100.93.gif](http://upload-images.jianshu.io/upload_images/2364940-550719b5d0bff3a0.gif?imageMogr2/auto-orient/strip)

---
#开源库、闭源库
---
- 开源库:能看到具体实现的代码(.m文件)。例如:AFNetworking、SDWebImage、MJRefresh
- 闭源库:实现的代码(.m)看不到,.m文件被加密成了.a文件。例如:Jpush、友盟、百度 
  - 闭源库分为:
    - 静态库: 以.a结尾 和.framework结尾
    - 动态库: 以.dylib结尾和.framework结尾

---
#MRC如何转成ARC
---
- 将MRC环境中的文件打包成静态库,直接就可以在ARC环境中使用了。


---
#打包静态库
---
#####1.Framework & Library-->Cocoa Touch Static Library-->创建成功,可看到小房子图标

![61-39.gif](http://upload-images.jianshu.io/upload_images/2364940-dab218ed8e5b59e0.gif?imageMogr2/auto-orient/strip)

#####2.在桌面新建一个文件夹,右键把文件名的后缀改为.bundle的,右键显示包内容将用到的图片放进包中,最后将包放到项目中
![61-40.gif](http://upload-images.jianshu.io/upload_images/2364940-ec27941f225a237c.gif?imageMogr2/auto-orient/strip)
#####3.创建类,写上代码,一定要选择Build Phases->Copy Files->添加类的头文件,让头文件参与编译,否则编译时不会生成.h文件
![61-41.gif](http://upload-images.jianshu.io/upload_images/2364940-3c2cbbc05952122d.gif?imageMogr2/auto-orient/strip)
#####4.打包静态库,Command+B编译模拟器状态的xcode项目,然后再Command+B编译真机状态的xcode项目,这样Products文件夹下的.a就会由红色变为黑色,右键.a文件,选择Show in Finder可以看到模拟机的文件夹和真机的文件夹,每个文件夹中都有静态库+声明文件

![61-42.gif](http://upload-images.jianshu.io/upload_images/2364940-fd8e51bb8f6197d9.gif?imageMogr2/auto-orient/strip)

#####5.将模拟器的静态库和真机的静态库合并成一个静态库,可以解决默认情况下真机文件夹下的静态库只能用于真机上,模拟器下的静态库只能用于模拟器下的问题。具体做法:终端输入cd xxx 切换到Xcode中的Products目录下,再输入lipo -create 模拟器的静态库1的路径 真机的静态库2的路径 -output 合并之后的文件名称,以后可以拿合并之后的文件名称,直接应用到模拟器上或者真机上都行。

![61-43.gif](http://upload-images.jianshu.io/upload_images/2364940-1e83811f96f108a3.gif?imageMogr2/auto-orient/strip)

#####6.将静态库(.a)+声明文件+项目中的.bundle文件放到一个Lib文件夹中,然后拖入到另一个项目中使用

![61-44.gif](http://upload-images.jianshu.io/upload_images/2364940-2421763fb0122df7.gif?imageMogr2/auto-orient/strip)

#####7.在另一个项目中导入Lib的类名,并调用类中的接口,具体实现的代码在加密的.a文件中

- 注意:调用loadLogoImage方法加载Bundle中的文件目录以及图片名时,一定要和真实的目录和图片名一致,如果有大小写字母不一致,那么在真机上是无法显示Bundle中的图片的,只是在模拟器中显示,因为苹果公司对手机app的代码的精确度要求的非常非常严。我的步骤7就是出现了Bundle文件夹的B我写成了小写的,就出现了上面提到的情况。

---
#####将真机的静态库文件放到模拟器中运行时会提示如下错误 或 者将模拟器的静态库文件放到真机中运行也会提示如下错误

![61-39.png](http://upload-images.jianshu.io/upload_images/2364940-0248326177b1cb49.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


#####解决办法:
- 将模拟器的静态库和真机的静态库合并成一个静态库,可以解决默认情况下真机文件夹下的静态库只能用于真机上,模拟器下的静态库只能用于模拟器下的问题。
- 即:lipo -create 模拟器的静态库1的路径 真机的静态库2的路径 -output 合并之后的文件名称


---
#精态库其他知识点
---
- 1.打包的静态库默认是打包的是Debug阶段的静态库,也可以改成Release阶段的静态库,但是最终都会生成这两个阶段的模拟器文件夹和真机文件夹
  - 真机的Debug版本
  - 真机的Release版本
  - 模拟器的Debug版本
  - 模拟器的Release版本

- 2.Debug版本和Release版本的比较  
 - 调试版本会包含完整的符号信息,以方便调试
 - 调试版本不会对代码进行优化
 - 发布版本不会包含完整的符号信息
 - 发布版本的执行代码是进行过优化的
 - 发布版本的大小会比调试版本的略小
 - 在执行速度方面,发布版本会更快些,但不意味着会有显著的提升

- 3.静态库的使用
 - 新建项目时,是将编译生成的.a静态库和 .h文件拖到新建的项目中使用的。
 - 动态库是不能上传到app store中的,静态库可以上传到app store

 
---
#打包动态库 
---

#####1.Framework & Library-->Cocoa Touch Framework-->创建成功,可看到工具箱图标

![61-46.gif](http://upload-images.jianshu.io/upload_images/2364940-c32059198c791c0e.gif?imageMogr2/auto-orient/strip)

#####2.在桌面新建一个文件夹,右键把文件名的后缀改为.bundle的,然后右键显示包内容将用到的图片放进包中,最后将包放到项目中

![61-47.gif](http://upload-images.jianshu.io/upload_images/2364940-591bb3de5e48609d.gif?imageMogr2/auto-orient/strip)

#####3.创建类,写上代码,一定要选择Build Phases->Headers->将Project选项中的.h文件拖动到Public选项中,目的就是让刚才创建的类参与编译,否则编译时不会生成.h文件

![61-48.gif](http://upload-images.jianshu.io/upload_images/2364940-ca4ae4c743562e2c.gif?imageMogr2/auto-orient/strip)

#####4.打包动态库,Command+B编译模拟器状态的xcode项目,然后再Command+B编译真机状态的xcode项目,这样Products文件夹下的.a就会由红色变为黑色,右键.a文件,选择Show in Finder可以看到模拟机的文件夹和真机的文件夹,每个文件夹中动态库,动态库中存储着未加密的.h文件和加密d但是你看不见的.m文件以及存储着图片的Bundle文件(只要动态库项目中有Bundle文件,那么打包动态库时,动态库会将将Bundle文件自动存储在自己的库中)

![61-49.gif](http://upload-images.jianshu.io/upload_images/2364940-6646378426684d2d.gif?imageMogr2/auto-orient/strip)

#####5.将模拟器的动态库和真机的动态库合并成一个动态库,可以解决默认情况下真机文件夹下的动态库只能用于真机上,模拟器下的动态库只能用于模拟器下的问题。具体做法:终端输入cd xxx 切换到Xcode中的Products目录下,再输入lipo -create 模拟器的动态库1的路径 真机佛你还态库2的路径 -output 合并之后的文件名称,以后可以拿合并之后的文件名称Dy,直接应用到模拟器上或者真机上都行。注意:两个动态库的路径是和Info.plist在目录中

![61-50.gif](http://upload-images.jianshu.io/upload_images/2364940-966aa6398d08ae8a.gif?imageMogr2/auto-orient/strip)

#####6.拷贝模拟器的动态库或者真机的动态库的任意一个就行,重用名为MergeDy,并将合并之后的文件Dy替换掉MergeDy中的Dy,然后拖入到另一个项目中使用

![61-51.gif](http://upload-images.jianshu.io/upload_images/2364940-fd525fda10d94091.gif?imageMogr2/auto-orient/strip)

#####7.运行则会提示image not found的错误,必须在General->Embedded Binaries中将动态库添加进去

![61-52.gif](http://upload-images.jianshu.io/upload_images/2364940-7fbd4c953e74f9ae.gif?imageMogr2/auto-orient/strip)

#####8.在另一个项目中导入#import ,并调用类中的接口即可


![61-53.gif](http://upload-images.jianshu.io/upload_images/2364940-4cc92d82a8111b02.gif?imageMogr2/auto-orient/strip)

---
#动态库其他知识点
---

- 1.默认创建的framework是动态库,改成静态库非常简单,即点击Build Settings-->Linking-->Mach-O Type->Static Library .
 -  如何验证改成了静态库?
   - 因为静态库不需要在General-->Embedded Binaries中导入framework就能运行成功,如果还是动态库的话,不导入framework会提示错误。所以,经过验证,不导入framework也能运行成功,说明是改为了静态库


- 2.添加的framework默认是动态库,必须在General->Embedded Binaries中将framework添加进来,否则提示image not found的错误
- 3.将模拟器的动态库和真机的动态库合并成一个动态库,可以解决默认情况下真机文件夹下的动态库只能用于真机上,模拟器下的动态库只能用于模拟器下的问题。

你可能感兴趣的:(集成极光推送、静态库、动态库)