推送通知

2020-03-24 04:28 来源:未知

一、推送通知

推送通知就是向用户推送一条信息来通知用户某件事件,可以在应用退到后台后,或者关闭后,能够通过推送一条消息通知用户某件事情,比如版本更新等等。

注意:

推送通知的常用应用场景:
  • 一些任务管理APP,会到任务时间即将到达时,通知你该做任务了。
  • 健身APP定时提醒你应该健身了。
  • 买过电影票,提前半个小时通知你,电影即将开场。
  • 当你QQ或微信收到信息时,即使退到后台,也可以收到信息通知你。
  • 电商APP,推送一条消息通知我们有新品上架等等。

UILocalNotification:本地通知,进行UI通知(iOS8以后也需要先注册通知授权)。
这两个类不在同一个框架中:
NSNotificationCenter在Foundation框架中
UILocalNotification在UIKit框架中

推送通知的常用展示样式:
  1. 屏幕顶部显示一块横幅
  1. 在锁屏界面显示一块横幅
  2. 更新APP图标数字
  3. 播放音效
  4. 屏幕中间弹出一个UIAlertView

本地推送

iOS7:不需要授权
iOS8:以后需要授权
步骤:
1、通过在AppDelegate中判断版本注册通知授权
2、在需要的界面创建一个本地通知,设置通知的属性,最后又AppDelegate调用通知

在#import "AppDelegate.h"中
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    if ([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0) {
        UIUserNotificationSettings *userNotification =  [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil ];
        [application registerUserNotificationSettings:userNotification];   
    }
    return YES;
}

在#import "ViewController.h"中
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
   // 1.创建本地通知
    UILocalNotification *localNote = [[UILocalNotification alloc] init];

    // 2.设置本地通知的内容
    // 2.1.设置通知发出的时间
    localNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:3.0];
    // 2.2.设置通知的内容
    localNote.alertBody = @"通知内容";
    // 2.3.设置滑块的文字
    localNote.alertAction = @"滑块文字";
    // 2.4.决定alertAction是否生效
    localNote.hasAction = NO;
    // 2.5.设置点击通知的启动图片
    localNote.alertLaunchImage = @"随便都可以";
    // 2.6.设置alertTitle
    localNote.alertTitle = @"123";
    // 2.7.设置有通知时的音效
    localNote.soundName = @"语音文件名";
    // 2.8.设置应用程序图标右上角的数字
    localNote.applicationIconBadgeNumber = 9;
    // 2.9.设置额外信息
    localNote.userInfo = @{@"type" : @1};

    // 3.调用通知
    [[UIApplication sharedApplication] scheduleLocalNotification:localNote];
}
Application代理方法的launchOptions属性
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions ;
launchOptions:用户直接打开程序的时候这个参数是没有值的。
若由其他应用程序通过openURL:启动,则UIApplicationLaunchOptionsURLKey对应的对象为启动URL(NSURL),
UIApplicationLaunchOptionsSourceApplicationKey对应启动的源应用程序的bundle ID (NSString);
若由本地通知启动,则UIApplicationLaunchOptionsLocalNotificationKey对应的是为启动应用程序的的本地通知对象(UILocalNotification);
若由远程通知启动,则UIApplicationLaunchOptionsRemoteNotificationKey对应的是启动应用程序的的远程通知信息userInfo(NSDictionary)
推送通知分为:
  1. 本地推送通知:不需要联网,在APP代码中推送的通知,确定知道未来某个时间点应该提醒用户什么【开发人员在APP内部通过代码发生 = 本地推送通知】
  1. 美高梅网投平台,远程推送通知:需要联网,是由服务器推送的通知,不确定未来某个时间点应该提醒用户什么【服务器可以确定通知时间和内容 = 远程推送通知】

使用原则:谁确定通知时间和内容,谁就可以发生

根据通知跳转到相应的界面
1、在AppDelegate中实现方法监听通知,判断是否进入后台,根据通知设置的额外信息userInfo来打开相应的界面。
// 应用程序在进入前台,或者在前台的时候都会执行该方法
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
    // 针对应用程序在后台的时候进行的跳转
    if (application.applicationState == UIApplicationStateInactive) {
        NSLog(@"进行界面的跳转");
        NSLog(@"%@", notification.userInfo);

        UIView *redView = [[UIView alloc] init];
        redView.frame = CGRectMake(0, 0, 100, 100);
        redView.backgroundColor = [UIColor redColor];
        [self.window.rootViewController.view addSubview:redView];
    }
}
2、当程序被杀死了,当再次点击进来是不会来到实现的代理方法,此时需要在程序加载完毕之后判断。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 界面的跳转(针对应用程序被杀死的状态下的跳转)
    if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
        // 跳转代码
        UILabel *redView = [[UILabel alloc] init];
        redView.frame = CGRectMake(0, 0, 200, 300);
        redView.numberOfLines = 0;
        redView.font = [UIFont systemFontOfSize:12.0];
        redView.backgroundColor = [UIColor redColor];
        redView.text = [NSString stringWithFormat:@"%@", launchOptions];
        [self.window.rootViewController.view addSubview:redView];
    }
    return YES;
}

二、本地推送通知

远程推送原理

一.什么是远程通知
概念:由服务器发送消息给用户弹出消息的通知(需要联网)
远程推送服务,又称为APNs(Apple Push Notification Services)
二.为什么需要远程通知
例子:淘宝最近双11搞活动,各种送红包,想告知用户.但是该用户不经常打包淘宝APP.淘宝如何通知该用户有最新的活动呢?
传统方式:只有用户打开了淘宝客户端,客户端向服务器请求是否有最新的活动,才能在APP中告知用户活动.
局限性:只要用户关闭了app,就无法跟app的服务器沟通,无法从服务器上获得最新的数据内容
远程通知的好处:不管用户打开还是关闭app,只要联网了,都能接收到服务器推送的远程通知

美高梅网投平台 1

屏幕快照 2016-06-05 下午12.38.44.png

本地推送通知步骤:
  1. 在iOS8以后使用本地推送通知,需要得到用户的许可
  1. 创建UILocalNotification本地通知对象,并设置必要属性
  2. 开始本地推送通知:第一种方法,延时推送,根据本地通知对象的fireDate设置进行本地推送通知
[[UIApplication shareApplication] scheduleLocalNotification:notification];

第二种方法,立刻推送,忽略本地通知对象的fireDate设置进行本地推送通知

[[UIApplication shareApplication] presentLocalNotificationNow:notification];
  1. 监听用户点击通知:
  • APP处于前台,此时不会弹框通知用户,但会调用对应的代理方法 :
-application:(UIApplication *)application didReceiveLocalNotification;
  • APP处于后台,屏幕上方会弹出横幅,用户点击横幅后,会进入前台,调用上面的代理方法。
  • APP已关闭,屏幕上方会弹出横幅,用户点击横幅后,会启动APP,调用以下方法:
-application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;/* 通过参数launchOptions获取本地推送通知内容 */UILocalNotification *local = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
  1. 调用UIApplication的对象方法,取消本地推送通知:
/* 取消指定的本地推送通知 */-cancelLocalNotification:(UILocalNotification *)notification;/* 取消全部本地推送通知 */-cancelAllLocalNotification;

如何做远程通知

需要真机,配置证书。
以微信客户端为例
1、客户端将手机的唯一标识UDID和应用程序的唯一标识Bound Identifier发送给苹果的APNs服务器。
2、苹果的APNs服务器根据这两个唯一标识生成一个加密的唯一标识deviceToken,并放回给客服端。
3、在AppDelegate中实现相应的方法拦截,并将这个deviceToken和微信帐号ID发送给客户端的服务器,客户端的服务器保存(deviceToke和微信帐号对应)。
4、当别人需要发送消息给特定的微信帐号好友,微信服务器将对应的帐号的deviceToken和消息发送给苹果的APNs服务器。
5、苹果的APNs服务器根据对应的deviceToken发送推送通知给微信客户端。
6、根据推送的消息,监听用户的点击(类似本地通知)

代码

#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//但程序被杀死,点击推送通知进入程序来到这,根据不同iOS版本进行通知的授权与注册
    if ([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0) { //iOS8
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
      //注册通知授权
        [application registerUserNotificationSettings:settings];
     //注册通知
        [application registerForRemoteNotifications];
    } else { // iOS7
        [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeNewsstandContentAvailability | UIRemoteNotificationTypeSound |UIRemoteNotificationTypeAlert];
    }

    if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
        // 跳转
    }
    return YES;
}

//拦截苹果APNs服务器返回的deviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    // 将DeviceToken传给服务器
    NSLog(@"%@", deviceToken.description);
}

//当程序从后台点击推送通知进入时会调用这个方法
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    NSLog(@"%@", userInfo);
}

//当程序进入后台,不点击推送消息,也会调用这个方法,但是发送的通知有固定的格式,1.需要打开后台模式 2.告诉系统是否有新内容的更新3、需要添加"content-available":"1";
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    NSLog(@"11111111");

    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = [UIColor redColor];
    redView.frame = CGRectMake(100, 100, 100, 100);
    [self.window.rootViewController.view addSubview:redView];

    // 1.需要打开后台模式 2.告诉系统是否有新内容的更新 3.发送的通知有固定的格式("content-available":"1")
    completionHandler(UIBackgroundFetchResultNewData);
}

设置应用程序右上角显示提示数字的两种方法

方法一:    [application setApplicationIconBadgeNumber:2]; (优先级高)
方法二:    UILocalNotification *localNote = [[UILocalNotification alloc] init];
   localNote.applicationIconBadgeNumber = 9;
以下是实例代码:

远程通知证书配置

1. 注册通知代码以及UIAlertView显示通知方法代码
- application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //因为是storyboard启动,这里就没有其他启动代码了 //iOS8.0以后,如果需要使用推送通知,需要得到用户许可 if (application.currentUserNotificationSettings.types == UIUserNotificationTypeNone) { //注册通知,有横幅通知、应用数字通知、应用声音通知 UIUserNotificationSettings * setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil]; [application registerUserNotificationSettings:setting]; } else { //当APP关闭后接收到通知,在启动中获取本地推送通知对象 UILocalNotification *notification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]; [self showLocalNotification:notification]; } return YES;}/* 弹框UIAlertView显示本地通知的信息 */- showLocalNotification:(UILocalNotification *)notification{ /* 显示本地通知 */ NSDictionary *userInfo = notification.userInfo; NSString *title = @"本地通知"; NSString *msg = userInfo[@"msg"]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:msg delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil]; [alert show]; //移除本地通知 [[UIApplication sharedApplication] cancelLocalNotification:notification];}

- .配置一个明确的APPID

  • 选择明确的APPID,并且将远程通知功能选中

美高梅网投平台 2

屏幕快照 2016-06-05 下午12.48.47.png

美高梅网投平台 3

屏幕快照 2016-06-05 下午12.49.27.png

  • 显示Push Notifications并非Enabled,而是Configurable.
![](https://upload-images.jianshu.io/upload_images/1965034-50b2ebecc9581f0a.png)

屏幕快照 2016-06-05 下午12.50.44.png

-   需要配置对应的证书
2. 创建本地通知代码
/* 创建一个本地通知 */- (UILocalNotification *)makeLocalNotification{ //创建本地推送通知对象 UILocalNotification *notification = [[UILocalNotification alloc] init]; //设置调用时间 notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:10.0];//通知触发的时间,10s以后 notification.repeatInterval = NSCalendarUnitMinute;//每隔多久重复发一次本地通知 //设置通知属性 notification.alertBody = @"最近添加了诸多有趣的特性,是否立即体验?";//通知主体 notification.applicationIconBadgeNumber = 1;//应用程序图标右上角显示的消息数 notification.alertAction = @"打开应用"; //待机界面的滑动动作提示 notification.alertLaunchImage = @"Default";//通过点击通知打开应用时的启动图片,这里使用程序启动图片 notification.soundName = UILocalNotificationDefaultSoundName;//收到通知时播放的声音,默认消息声音 //设置用户信息 notification.userInfo = @{ @"id":@1, @"user":@"Kenshin Cui", @"msg":@"我来了一发本地通知"};//绑定到通知上的其他附加信息 return notification;}

如果需要每天的中午12点准时本地推送怎么办呢?就像这么办,修改fireDaterepeatInterval属性

NSDateFormatter *formatter1 = [[NSDateFormatter alloc]init]; [formatter setDateFormat:@"yyyy-MM-dd HH-mm-sss"]; NSDate *resDate = [formatter dateFromString:@"2016-04-09 12-00-00"];notification.fireDate = resDate;//设定为明天中午12点触发通知//记得设置当前时区,没有设置的话,fireDate将不考虑时区,这样的通知会不准确notification.timeZone = [NSTimeZone defaultTimeZone];notification.repeatInterval = NSCalendarUnitDay;//每隔一天触发一次

二 证书的配置

  • 在Certificates中配置证书
    • 选择证书的类型(调试和发布都需要配置)

美高梅网投平台 4

屏幕快照 2016-06-05 下午12.52.15.png

  • 选择为哪一个APPID配置证书
![](https://upload-images.jianshu.io/upload_images/1965034-514e49386b365c0b.png)

屏幕快照 2016-06-05 下午12.53.50.png
  • 其他步骤同真机调试和发布程序

  • 配置完成后获得两个证书文件

![](https://upload-images.jianshu.io/upload_images/1965034-ceaaabbdb48f7568.png)

屏幕快照 2016-06-05 下午12.54.43.png
  • 配置描述文件

美高梅网投平台 5

屏幕快照 2016-06-05 下午12.55.15.png

  • 和真机描述文件完全一致
3. 监听用户点击
/* 注册本地通知完成会调用,即用户点击确定授权后调用 */- application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings{ //在这里我们尝试发送本地推送通知 if (notificationSettings.types != UIUserNotificationTypeNone) { UILocalNotification *notification = [self makeLocalNotification]; //延迟调用通知 [application scheduleLocalNotification:notification]; //立刻发送通知 //[application presentLocalNotificationNow:notification]; }}/* 应用还在运行,无论前台还是后台,都会调用该方法处理通知 */- application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{ if( notification ) { [self showLocalNotification:notification]; }}/* 应用进入前台,去除应用边角数字显示 */- applicationWillEnterForeground:(UIApplication *)application { //去除应用边角数字 [application setApplicationIconBadgeNumber:0];}

美高梅网投平台 6本地通知弹出通告栏和应用边角数字变化美高梅网投平台 7显示本地通知

获取DeviceToken

1.在苹果的APNs服务器注册,以获取DeviceToken
通常在didFinishLaunchingWithOptions中添加如下代码进行注册

if ([UIDevice currentDevice].systemVersion.doubleValue >= 8.0) {
        // 1.向用户请求可以给用户推送消息
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
        [application registerUserNotificationSettings:settings];

        // 2.注册远程通知(拿到用户的DeviceToken)
        [application registerForRemoteNotifications];
    } else {
        [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
    }

注册之后在另外一个代理方法中,拿到DeviceToken

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    // 5e8cf393 9e950137 86ac8375 12185078 19eb3ebd 936777e1 f061caec a48cb236
    // 将用户的用户名和deviceToken发送给服务器,让服务器进行保存备份即可
    NSLog(@"%@", deviceToken);
}
  • 将DeviceToken发送到服务器即可

三、远程推送通知

美高梅网投平台 8iOS远程消息推送的工作机制

测试远程通知

  • 当前我们没有自己的服务器,如何测试?

  • 可以使用一个第三方的Mac程序来测试:PushMeBaby

  • 使用该程序需要修改一些内容

    • 编译程序,报错的行注释掉
    ![](https://upload-images.jianshu.io/upload_images/1965034-098bab1531514047.png)

    屏幕快照 2016-06-05 下午1.00.02.png
  • 运动pushMeBaby程序

![屏幕快照 2016-06-05 下午1.00.42.png](http://upload-images.jianshu.io/upload_images/1965034-16133560df57e119.png?
imageMogr2/auto-orient/strip|imageView2/2/w/1240)

注意:填写的内容
填写推送给的DeviceToken
添加推送的内容:固定格式
{"aps":{"alert":"弹出的信息","badge":1,"sound":"声音","info":"额外信息"}}

ios10推送介绍

iOS远程消息推送步骤:
  1. 应用服务提供商从服务器端把要发送的消息设备令牌(device token)发送给苹果的消息推送服务器APNs
  1. APNs根据设备令牌在已注册的设备(iPhone、iPad、iTouch、Mac等)查找对应的设备,将消息发送给相应的设备。
  2. 客户端设备接将接收到的消息传递给相应的应用程序,应用程序根据用户设置弹出通知消息。
下面是更详细的流程:

美高梅网投平台 9远程推送详细流程图

所有的苹果设备,在联网状态下,都会和苹果服务器APNs建立一个长连接

  • 长连接:服务器可以向客户端发送消息,保证数据的即时性,但比较占用资源
  • 短连接:服务器无法主动向客户端发消息,会话结束后,就立即释放资源,节省资源

远程推送通知就是借助苹果设备与APNs服务器之间的长连接,借助APNs服务器讲消息发送给客户端。

远程推送通知实现的条件:
  1. 必须有真机,只有真机具备UDID,才能生成deviceToken设备令牌
  1. 需要开发推送Cer证书

证书的申请请参考:iOS学习笔记21-推送证书与秘钥申请

deviceToken的生成算法只有Apple掌握,为了确保算法发生变化后仍然能够正常接收服务器端发送的通知,每次应用程序启动都重新获得deviceToken

远程推送通知步骤:
  1. iOS8以后,使用远程通知,需要请求用户授权
  1. 注册远程通知成功后会调用以下方法,获取deviceToken设备令牌:
-application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken;
  1. deviceToken设备令牌发送给服务器,时刻保持deviceToken是最新的
  2. 监听远程推送通知:
-application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;
下面是实例代码:
1. 注册远程推送通知代码:
- application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ //iOS8.0以后,如果需要使用本地推送通知,需要得到用户许可 if (![application isRegisteredForRemoteNotifications]) { UIUserNotificationSettings * setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil]; [application registerUserNotificationSettings:setting]; //注册远程推送通知 [application registerForRemoteNotifications]; } return YES;}
2. 注册成功调用代码:
/* 注册远程推送通知成功会调用 ,在此接收设备令牌deviceToken */- application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken{ [self addDeviceToken:deviceToken];}/* 保存deviceToken,并同步服务器上保存的deviceToken,以便能正确推送通知 */- addDeviceToken:deviceToken{ NSString *key = @"DeviceToken"; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; //取出原来的deviceToken,进行比较 NSData *oldToken = [defaults objectForKey:key]; if ([oldToken isEqualToData:deviceToken]) { //存入新的deviceToken [defaults setObject:deviceToken forKey:key]; [defaults synchronize]; //发送网络请求到服务器,说明deviceToken发生了改变 [self sendDeviceTokenWithOldDeviceToken:oldToken newDeviceToken:deviceToken]; }}/* 发送网络请求到服务器,说明deviceToken发生了改变,服务器那边也要同步改变 */- sendDeviceTokenWithOldDeviceToken:oldToken newDeviceToken:newToken{ //发送到服务器,下面是服务器的一个接口 NSString *urlStr = @"http://192.168.1.101/RegisterDeviceToken.aspx"; urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSURL *url = [NSURL URLWithString:urlStr]; //POST网络请求 NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:url]; requestM.HTTPMethod = @"POST"; //POST请求的请求体 NSString *bodyStr = [NSString stringWithFormat:@"oldToken=%@&newToken=%@",oldToken,newToken]; requestM.HTTPBody = [bodyStr dataUsingEncoding:NSUTF8StringEncoding]; //使用会话来发送网络请求 NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:requestM completionHandler:^(NSData *data,NSURLResponse *response,NSError *error){ if{ NSLog(@"Send Success !"); } else { NSLog(@"Send Failure, error = %@",error.localizedDescription); } }]; //网络请求任务启动 [dataTask resume];}
3. 监听远程推送通知:
/* 收到远程推送通知时会调用 */- application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{ NSString *title = @"远程推送通知"; NSString *msg = userInfo[@"msg"]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:msg delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil]; [alert show];}

四、第三方远程推送

上面的远程推送过程如果觉得实现比较麻烦,你可以使用第三方推送,例如:

  • 极光推送,我只用过这个,界面还不错,这不是在打广告!
  • 个推
  • 腾讯信鸽

具体的集成步骤及使用方法,请查看对应的官方文档,非常详细。

如果有什么问题或建议,可以再下方评论区提出,求关注,求打赏!OO哈!
TAG标签:
版权声明:本文由美高梅网投平台发布于美高梅简介,转载请注明出处:推送通知