精华内容
下载资源
问答
  • 个推的使用

    热门讨论 2014-04-28 09:19:25
    可以为手机端的app使用者送消息,而不是通过手机上的app对用户发送消息。
  • 个推消息推送demo

    2016-05-18 09:48:41
    1、个推推送透传消息的实现 2、消息在通知栏中显示 3、点击通知栏进入相应页面 4、工程目录结构介绍及效果展示
  • 1.第三方应用集成个推SDK,个推SDK运行后获取CID返回给第三方应用,由第三方应用保存至其应用服务器; 2.第三方应用服务器调用推送API进行消息推送,个推SDK将接收到的推送消息回调给App进行处理。 二、推送方式 ...

    背景

    说明文档这个事情官方应该提供出来,可惜官方觉得是多余的,免费的东西凭啥给你做好。于是我在这里叙述一下实现消息通知推送的步骤。

    uni-app官方文档入口
    https://uniapp.dcloud.io/api/plugins/push

    uniPush官方使用指南
    https://ask.dcloud.net.cn/article/35622

    个推官方文档入口
    https://docs.getui.com/

    推送H5+API接口:
    https://www.html5plus.org/doc/zh_cn/push.html

    一、流程

    1.第三方应用集成个推SDK,个推SDK运行后获取CID返回给第三方应用,由第三方应用保存至其应用服务器;
    2.第三方应用服务器调用推送API进行消息推送,个推SDK将接收到的推送消息回调给App进行处理。

    二、推送方式

    个推提供JAVA、C#、PHP、Python等多种语言版本的服务端API SDK,可以和各种第三方应用服务器技术架构进行对接。为了最大程度提高消息推送性能,第三方开发者需要根据业务需求合理选择消息推送形式。如果是针对每 个用户进行定制化的消息推送、或是实现类似IM的点对点消息,请采用单推消息形式(SingleMessage);如果需要根据特定条件筛选出一批CID 后推送相同的内容,请选择批量推送形式(ListMessage);如果希望针对省市或全量用户进行推送,请选择群推形式(AppMessage)。

    通过上面描述已经大概了解个推了,可以单推、批量推、按照筛选条件批量推送,详细更多介绍请参考官方文档:http://docs.getui.com/

    三、基础环境准备

    2.1 DCLOUD平台配置
    参考官方教程在dcloud中配置各个厂商的api和secret,这部分不是难点,有问题留言。
    https://ask.dcloud.net.cn/article/35716
    在这里插入图片描述

    为啥要配置厂商呢:
    为了在app关闭的时候,可以通过厂商的服务器推送消息给手机通知系统。第三方的消息推送会被阻挡,最好的方式就是按照厂商的要求接入各个推送服务。庆幸的事情,这部分DCLOUD已经帮你做好了。你只需要注册下各个厂商的开发平台,按到appid和secret登录dcloud后台即可。
    在这里插入图片描述
    2.1 uni-app权限配置
    在这里插入图片描述

    2.3 准备自定制测试基座或者云打包
    Hbuilder的基座配置的信息都是dcloud的,所以用被人的app是没办法测试推送服务的。解决这个问题有两种
    1,云打包时打包成为自己的app后测试
    2,制作自定义的基座(很简单),这个基座的信息都是自己的,所以可以测试
    运行的时候选择自定制基座,或者直接云打包后的的apk安装到手机测试。
    在这里插入图片描述
    温馨提示: 可以先体验 uni push 后台界面推送(帮助理解推送的过程)

    四、APP端代码

    代码位置只能在app.vue的onLaunch中,其他地方可能会有问题。

     //#ifdef APP-PLUS  
    			 var info = plus.push.getClientInfo();
    			console.log( JSON.stringify( info ) );
    			 /* 5+  push 消息推送 ps:使用:H5+的方式监听,实现推送*/  
    			plus.push.addEventListener("click", function(msg) {  
    						console.log("click:"+JSON.stringify(msg));  
    						console.log(msg.payload);  
    						console.log(JSON.stringify(msg));  
    						//这里可以写跳转业务代码
    					}, false);  
    						// 监听在线消息事件    
    					plus.push.addEventListener("receive", function(msg) {  
    						// plus.ui.alert(2);  
    							//这里可以写跳转业务代码
    						console.log("recevice:"+JSON.stringify(msg))  
    			   }, false);  
    
    		   //#endif  
    
    

    这里就是官方文档比较恶心的地方,自己生命onpush之类的api废弃了,但是给的demo还是用的废弃的方式。推荐的H5+api却不给demo。要知道demo对我们就是api文档啊。

    这里listener监听的两种事件

    1. “click”-从系统消息中心点击消息启动应用事件;
    2. “receive”-应用从推送服务器接收到推送消息事件。

    五、后端代码(java)

    5.1个推sdk导入

    <dependency>
        <groupId>com.gexin.platform</groupId>
        <artifactId>gexin-rp-sdk-http</artifactId>
        <version>4.1.0.5</version>
    </dependency>
    
    <repositories>
        <repository>
            <id>getui-nexus</id>
            <url>http://mvn.gt.igexin.com/nexus/content/repositories/releases/</url>
        </repository>
     </repositories>
    

    5.2 加入 uin push 应用配置参数,实际中替换为自己的

    	public static final String AppID = "";
    	public static final String AppSecret = "";
    	public static final String AppKey = "";
    	public static final String MasterSecret = "";
    	public static final String HOST = "http://sdk.open.api.igexin.com/apiex.htm";
    

    第一个推送方式,也是最常用性能最高的推送,单推:

    	/**
    	 * 
    	 * @param cidOrAlias
    	 *            别名或者cid
    	 * @param msg
    	 *            透传消息内容
    	 * @param type
    	 *            1-cid推,2-别名推
    	 */
    	public static void pushToSingle(String cidOrAlias, String msg, int type) {
    		IGtPush push = new IGtPush(HOST, AppKey, MasterSecret);
    		ITemplate template = buildTransmissionTemplate(msg);
    		SingleMessage message = new SingleMessage();
    		// 是否离线推送
    		message.setOffline(true);
    		// 离线有效时间,单位为毫秒,可选
    		message.setOfflineExpireTime(24 * 3600 * 1000);
    		// 消息内容
    		message.setData(template);
    		// 可选,1为wifi,0为不限制网络环境。根据手机处于的网络情况,决定是否下发
    		message.setPushNetWorkType(0);
     
    		Target target = new Target();
    		target.setAppId(AppID);
    		if (type == 1) {
    			target.setClientId(cidOrAlias);
    		} else if (type == 2) {
    			// 按别名推送
    			target.setAlias(cidOrAlias);
    		}
    		IPushResult ret = null;
    		try {
    			ret = push.pushMessageToSingle(message, target);
    		} catch (RequestException e) {
    			e.printStackTrace();
    			// 推送失败时,进行重推
    			ret = push.pushMessageToSingle(message, target, e.getRequestId());
    		}
    		if (ret != null) {
    			System.out.println(ret.getResponse().toString());
    		} else {
    			System.out.println("服务器响应异常");
    		}
    	}
    

    上面有详细的注释,有几个需要注意几个地方。

    推送的消息类型,支持各种模板,有通知栏透传模板,通知栏点击跳转网页模板,透传模板等,下面列举示例

    1、通知栏点击跳转网页模板:

    public static LinkTemplate buildLinkTemplate() {
    		LinkTemplate template = new LinkTemplate();
    		// 设置APPID与APPKEY
    		template.setAppId(AppID);
    		template.setAppkey(AppKey);
     
    		Style0 style = new Style0();
    		// 设置通知栏标题与内容
    		style.setTitle("请输入通知栏标题");
    		style.setText("请输入通知栏内容");
    		// 配置通知栏图标
    		style.setLogo("icon.png");
    		// 配置通知栏网络图标
    		style.setLogoUrl("");
    		// 设置通知是否响铃,震动,或者可清除
    		style.setRing(true);
    		style.setVibrate(true);
    		style.setClearable(true);
    		template.setStyle(style);
     
    		// 设置打开的网址地址
    		template.setUrl("http://www.baidu.com");
    		return template;
    	}
    

    通过这种方式推送,手机上会收到一条通知栏消息,点击后会打开指定网页。

    2、通知栏透传模板

    	public static NotificationTemplate buildNotificationTemplate() {
    		NotificationTemplate template = new NotificationTemplate();
    		// 设置APPID与APPKEY
    		template.setAppId(AppID);
    		template.setAppkey(AppKey);
     
    		Style0 style = new Style0();
    		// 设置通知栏标题与内容
    		style.setTitle("群推通知栏标题");
    		style.setText("群推通知栏内容");
    		// 配置通知栏图标
    		style.setLogo("icon.png");
    		// 配置通知栏网络图标
    		style.setLogoUrl("");
    		// 设置通知是否响铃,震动,或者可清除
    		style.setRing(true);
    		style.setVibrate(true);
    		style.setClearable(true);
    		template.setStyle(style);
     
    		// 透传消息设置,1为强制启动应用,客户端接收到消息后就会立即启动应用;2为等待应用启动
    		template.setTransmissionType(2);
    		template.setTransmissionContent("请输入您要透传的内容");
    		return template;
    	}
    

    通过这种方式,手机上会收到一条通知栏消息,并且带有透传消息。

    3、纯透传模板:

    	public static NotificationTemplate buildNotificationTemplate() {
    		NotificationTemplate template = new NotificationTemplate();
    		// 设置APPID与APPKEY
    		template.setAppId(AppID);
    		template.setAppkey(AppKey);
     
    		Style0 style = new Style0();
    		// 设置通知栏标题与内容
    		style.setTitle("群推通知栏标题");
    		style.setText("群推通知栏内容");
    		// 配置通知栏图标
    		style.setLogo("icon.png");
    		// 配置通知栏网络图标
    		style.setLogoUrl("");
    		// 设置通知是否响铃,震动,或者可清除
    		style.setRing(true);
    		style.setVibrate(true);
    		style.setClearable(true);
    		template.setStyle(style);
     
    		// 透传消息设置,1为强制启动应用,客户端接收到消息后就会立即启动应用;2为等待应用启动
    		template.setTransmissionType(2);
    		template.setTransmissionContent("请输入您要透传的内容");
    		return template;
    	}
    

    客户端集成SDK设置监听后,会收到透传消息,客户端可以自己灵活的选择处理方式。

    上面还提到按别名推送,那么别名是怎么来的呢

    	public static void bindAlias(String cid, String alias) {
    		IGtPush push = new IGtPush(HOST, AppKey, MasterSecret);
    		IAliasResult bindSCid = push.bindAlias(AppID, alias, cid);
    		System.out.println("绑定结果:" + bindSCid.getResult() + "错误码:" + bindSCid.getErrorMsg());
    	}
    

    这是绑定别名的方法,这样通过绑定别名可以和自己的业务数据绑定进行推送。单推就介绍到这里。

    第二种推送方式:批量推送:

    	public static void pushToList(List<String> cids, String msg) {
    		// 配置返回每个用户返回用户状态,可选
    		System.setProperty("gexin_pushList_needDetails", "true");
    		// 配置返回每个别名及其对应cid的用户状态,可选
    		// System.setProperty("gexin_pushList_needAliasDetails", "true");
    		IGtPush push = new IGtPush(HOST, AppKey, MasterSecret);
    		// 透传模板
    		ITemplate template = buildTransmissionTemplate(msg);
    		ListMessage message = new ListMessage();
    		message.setData(template);
    		// 设置消息离线,并设置离线时间
    		message.setOffline(true);
    		// 离线有效时间,单位为毫秒,可选
    		message.setOfflineExpireTime(24 * 1000 * 3600);
    		// 配置推送目标
    		List<Target> targets = new ArrayList<Target>();
    		Target target = null;
    		for (String cid : cids) {
    			target = new Target();
    			target.setAppId(AppID);
    			target.setClientId(cid);
    			targets.add(target);
    			// target.setAlias(Alias1);
    		}
    		// taskId用于在推送时去查找对应的message
    		String taskId = push.getContentId(message, "任务别名_toApp");
    		// String taskId = push.getContentId(message);
    		IPushResult ret = push.pushMessageToList(taskId, targets);
    		System.out.println(ret.getResponse().toString());
    	}
    

    这里实际上就是,对一批指定cliendid的用户进行推送,也支持上面的几种模板,参数也可以传别名集合进来。

    第三种推送方式,按各种筛选条件进行群推:

    public static void pushToApp(String msg, List<String> tagList) throws Exception {
    		IGtPush push = new IGtPush(HOST, AppKey, AppSecret);
     
    		// 使用通知栏链接模板
    		ITemplate template = buildLinkTemplate();
    		AppMessage message = new AppMessage();
    		message.setData(template);
     
    		message.setOffline(true);
    		// 离线有效时间,单位为毫秒,可选
    		message.setOfflineExpireTime(24 * 1000 * 3600);
    		// 可选,1为wifi,0为不限制网络环境。根据手机处于的网络情况,决定是否下发
    		message.setPushNetWorkType(0);
    		// 全量推送个推控制下发速度在100条/秒,只有toApp支持定速推送。
    		// message.setSpeed(100);
    		// 设置指定时间推送
    		// message.setPushTime("201903271756");
     
    		List<String> appIdList = new ArrayList<String>();
    		appIdList.add(AppID);
    		message.setAppIdList(appIdList);
     
    		// 推送给App的目标用户需要满足的条件
    		AppConditions cdt = new AppConditions();
     
    		// 手机类型
    		List<String> phoneTypeList = new ArrayList<String>();
    		phoneTypeList.add("ANDROID");
    		phoneTypeList.add("IOS");
     
    		// 省份
    		List<String> provinceList = new ArrayList<String>();
    		// 50000000代表重庆市
    		provinceList.add("50000000");
     
    		// 设置手机类型筛选
    		cdt.addCondition(AppConditions.PHONE_TYPE, phoneTypeList);
    		// 设置省份筛选
    		cdt.addCondition(AppConditions.REGION, provinceList);
    		// 设置tag筛选
    		cdt.addCondition(AppConditions.TAG, tagList);
     
    		// 交并补
    		// cdt.addCondition(AppConditions.PHONE_TYPE, phoneTypeList,
    		// OptType.or);
    		// cdt.addCondition(AppConditions.REGION, provinceList, OptType.or);
    		// cdt.addCondition(AppConditions.TAG, tagList, OptType.or);
    		message.setConditions(cdt);
     
    		IPushResult ret = push.pushMessageToApp(message, "任务别名_toApp");
    		System.out.println(ret.getResponse().toString());
    	}
    

    几个注意事项:

    省份和城市编码,请参考官方文档

    定速推送:旨在解决个推群推系统在全量推送时速度过快,导致部分客户服务器连接压力过大的问题。提供接口设置让用户按自身情况控制推送速度,如果未设置则按默认推送速度发送。

    定时推送:对单个指定应用的所有用户群发推送消息。该消息可以在用户设定的时间点进行推送。此接口需要开通。

    交并补设置:应用群推对于复杂的查询条件新增加的交并补功能,以对应查询语义中的与或非的关系

    • 场景:需要发送给城市在A,B,C里面,没有设置tagtest标签,手机型号为android的用户,用条件交并补功能可以实现,city(A|B|C)
      && !tag(tagtest) && phonetype(andriod)
    • 条件类型(OptType.or 或, OptType.and 与, OptType.not 非)

    tag列表:上面有提到tag,tag就是给用户打的标签,可以实现按标签推送,tag的设置方式如下:

    public static void setTag(String cid, List<String> tagList) {
    		IGtPush push = new IGtPush(HOST, AppKey, MasterSecret);
    		IQueryResult ret = push.setClientTag(AppID, cid, tagList);
    		System.out.println(ret.getResponse().toString());
    	}
    

    通过设置标签,所有终端都可以设置一个或者多个标签,进行标签推送时就会实现筛选作用。

    群推就介绍到这里。

    单推还有一种扩展形式,批量单推,用于一次创建提交多个单推任务。当单推任务较多时,推荐使用该接口,可以减少与服务端的交互次数。

    public static void pushBatch(String cid, String content) throws Exception {
    		IIGtPush push = new IGtPush(HOST, AppKey, MasterSecret);
    		IBatch batch = push.getBatch();
    		try {
    			// 构建透传消息
    			constructClientTransMsg(cid, content, batch);
    			// 构建点击通知打开网页消息
    			constructClientLinkMsg(cid, content, batch);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		batch.submit();
    	}
    
    private static void constructClientTransMsg(String cid, String msg, IBatch batch) throws Exception {
    		SingleMessage message = new SingleMessage();
    		TransmissionTemplate template = new TransmissionTemplate();
    		template.setAppId(AppID);
    		template.setAppkey(AppKey);
    		template.setTransmissionContent(msg);
    		// 这个Type为int型,填写1则自动启动app
    		template.setTransmissionType(1);
     
    		message.setData(template);
    		message.setOffline(true);
    		message.setOfflineExpireTime(1 * 1000);
     
    		// 设置推送目标,填入appid和clientId
    		Target target = new Target();
    		target.setAppId(AppID);
    		target.setClientId(cid);
    		batch.add(message, target);
    	}
    
    private static void constructClientLinkMsg(String cid, String msg, IBatch batch) throws Exception {
    		SingleMessage message = new SingleMessage();
    		LinkTemplate template = new LinkTemplate();
    		template.setAppId(AppID);
    		template.setAppkey(AppKey);
    		template.setTitle("title");
    		template.setText("msg");
    		template.setLogo("push.png");
    		template.setLogoUrl("logoUrl");
    		template.setUrl("url");
     
    		message.setData(template);
    		message.setOffline(true);
    		message.setOfflineExpireTime(1 * 1000);
     
    		// 设置推送目标,填入appid和clientId
    		Target target = new Target();
    		target.setAppId(AppID);
    		target.setClientId(cid);
    		batch.add(message, target);
    	}
    

    这样就可以实现一次服务端交互,完成多个单推任务,cid也可以是不同的,给不同的终端进行推送,推送内容也可以不同,这里为了简便就取的一样的。

    个推java服务端核心API就介绍到这里,官网还有很多辅助API,查询统计,用户,推送结果等等,这里就不一一列举了,有这个需求的请移至官网文档详细阅读。

    展开全文
  • 个推使用指南

    千次阅读 2018-09-14 17:31:13
    按照个推文档CocoaPods集成,基本能实现个推的基本推送功能。但是很多细节文档没有说,我就走了很多弯路。 首先登录个推网站。在个推·消息推送登记应用。 要登记测试环境和生产环境两个应用。 点击应用...

    按照个推文档CocoaPods集成,基本能实现个推的基本推送功能。但是很多细节文档没有说,我就走了很多弯路。
    第一步:首先登录个推网站,注册用户并登录。
    第二步:在个推·消息推送登记应用。
    这里写图片描述
    要登记测试环境和生产环境两个应用。
    这里写图片描述
    第三步:点击应用配置,显示上图页面,上传或修改开发环境的p12正书。设置证书密码,这个密码要和p12证书(《制作p12证书》)的密码一致。然后点击测试一下。
    这里写图片描述
    注意:证书测试就是apns测试,走的是苹果推送服务器。
    没有什么好说的,运行你集成了个推的应用,把打印deviceToken输入对话框就能测试apns推送了。也可以创建透传消息进行测试了。个推网站只支持发送透传消息。证书测试时是测试的apns消息。
    遇到的问题1:在苹果的远程通知注册成功委托函数didRegisterForRemoteNotificationsWithDeviceToken中获得token成功,然后修改别名: [GeTuiSdk bindAlias:@“个23推11” andSequenceNum:@“s1eq-1”]; 那两个参数我无论怎么改都是报30002错误,
    这里写图片描述
    我可是按照文档来的的啊!
    这里写图片描述
    为何文档上把上面的例子的格式推翻了呢?为何不举一个标准的别名例子呢?
    这里写图片描述
    这里写图片描述

    - (void)GeTuiSdkDidRegisterClient:(NSString *)clientId
    {
        FLDDLogDebug(@"函数 clientId:%@", clientId);
        if(!isEmptyString(clientId) && (!self.clientId || ![clientId isEqualToString:self.clientId]))
        {
            NSLog(@"clientId:%@", clientId);
            //        [GeTuiSdk bindAlias:@"y790715966c94d93e84182fbfce36182123456GS" andSequenceNum:@"1sssas2223446"];
            if(self.payloadFlag && !self.noFirstGetClientIdFlag)
            {
                [GeTuiSdk resetBadge]; //重置角标计数
                [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; // APP 清空角标
            }
            self.noFirstGetClientIdFlag = YES;
            self.payloadFlag = NO;
            
    //        [GeTuiSdk resetBadge]; //重置角标计数
    //        [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; // APP 清空角标
            
    //        [[NSNotificationCenter defaultCenter] postNotificationName:@"submitNotification" object:nil userInfo:@{@"clientId":clientId}];
            [self submitWithUserInfo:@{@"clientId":clientId}];
        }
    }
    
    

    通过这个问题,大家知道了吧!cid回调以后,调用设置标签,别名绑定等接口,清除角标。
    遇到的问题2:我在个推网站测试时,证书测试正常,但是测试推送消息时,有很多消息我手机收不到。咨询了客服还是找不到,在下班时突然收到一条推送消息。第二天我继续定位。

    5.2 苹果 APNs 静默推送
    如果需要使用 静默推送(Remote Notifications)功能,请在推送时指定content-available:1参数。
    

    根据文档apns推送content-available为1。
    这里写图片描述
    这里写图片描述
    这里写图片描述
    可以看到个推测试网站说iOS只支持透传消息,当然apns也可以测试,那就是证书测试。当设置content-available为1时,下面的title和body输入框变灰色,没有办法输入,但是若先输入内容再选择为1,那里面也有内容。结果我推送这样的消息,手机是收不到消息的。文档上不是说content-available:1是静默推送(apns)吗?文档和测试网站的配置为何有看似相互矛盾的说明和配置呢?我本着宁可错过不可放过的原则,把content-available选择为0,title和body输入框可以输入了,输入内容,应用在后台时终于收到消息了。但是在前台时仍旧收不到消息。然后就检查个推的接口函数,发现是拷贝的以前个推的老函数,以前在做曹操专车时用的也个推,那时候个推比较老,现在新的个推函数很多都变了。是应用在前台时,被透传函数收到了,只是我没有把透传函数名(GeTuiSdkDidReceivePayloadData)写正确,写的是老函数名(GexinSdkDidReceivePayload)。后来咨询个推客服,他们说个推现在服务端只支持iOS的透传模版。应用在前台收透传消息,在后台收apns消息。我被这个content-available要搞的脑神经分裂了,切记切记。
    遇到的问题3:然后和服务器联调发现,在个推网站测试能收到开发环境证书的应用推送来的消息。收不到服务发送来推送消息,安卓手机测试时可以收到消息。于是就各种的着急。服务开发给的答复,他是按照个推文档第一个点击通知打开应用模板推送的消息。我让他试一试其它推送模版。测试发现只有第4个透传消息模版推送的消息,app能收到。
    这里写图片描述
    后来咨询个推客服,他说服务器向iOS普通推送时只能使用第4个透传消息模版推送的消息。
    遇到的问题4:我们的领导要求像其它的应用,无论应用在前台和后台都要能收到系统状态栏的消息。
    我的思路是:应用在后台消息自动出现在系统消息栏,在前台收到消息自己显示本地通知消息。具体的说是,应用在后台或应用没有启动,很简单走的是apns通道,这个你可以不需要管,若你的手机按装你的应用的情况下,消息会出现在系统消息栏。在你应用在前台时,走的是透传消息,被GeTuiSdkDidReceivePayloadData函数(早期的个推函数是GexinSdkDidReceivePayload。注意早期个推和新的个推函数的变更。这个我走了半天弯路。)接收,不走apns消息通道,走的是个推服务器和app直接的长连接通道,然后自己弹出本地日历通知。

                    UILocalNotification *notification = [[UILocalNotification alloc] init];
                    if (notification != nil) {
                        // 设置推送时间
                        notification.fireDate = [NSDate date];
                        // 设置时区
                        notification.timeZone = [NSTimeZone defaultTimeZone];
                        // 设置重复间隔
                        notification.repeatInterval = 0;
                        // 推送声音
                        notification.soundName = UILocalNotificationDefaultSoundName;
                        if (@available(iOS 8.2, *)) {
                            notification.alertTitle = title;
                        } else {
                            // Fallback on earlier versions
                        }
                        // 推送内容
                        notification.alertBody = body;
                        notification.userInfo = jsonObject;
                        notification.category = payloadMsg;
                        //显示在icon上的红色圈中的数子
                        notification.applicationIconBadgeNumber =0;
                        //添加推送到UIApplication
                        UIApplication *app = [UIApplication sharedApplication];
                        [app scheduleLocalNotification:notification];
                    }
    

    这里写图片描述
    注意:这个通知本质是一个日历事件,可以部分模拟系统通知,但不能完全代替。iOS8.2之前只能设置消息内容,不能设置消息标题。iOS8.2及以后只能设置消息内容和标题,不能设置payload等自定义键值对。透传函数收到的是推送的消息内容,title和body都看不到。详细见个推发送消息各字段在系统状态栏显示的信息,点击消息图标激活应用传递的信息,应用在线收到的透传消息信息。若消息内容含有title和body键值 json串,就可以解析出来弹出本地通知。
    遇到的问题5:应用在前台,由于弹出的是本地通知(日历事件),而它最多只能携带标题和内容,无法携带自定义payload字段。所以无法实现拉掉应用,点击消息图标打开app并进入对应消息页面。
    这里写图片描述
    这里写图片描述
    咨询个推客服,他说应用在线时只能走透传弹出本地通知。看来既然用个推就要遵循个推的规则。这个是框架问题,不是技术问题。安卓手机,无论应用是否在线都是把消息显示在系统消息栏中,点击消息,若应用不在线直接打开应用进入对应页面。看来苹果手机和安卓手机的应用也很难做到这方面的统一,不知道除个推外的第三方推送的逻辑是否和它一样。
    遇到的问题6:我想在个推网站发送推送消息时,只给我的测试手机。个推提送了推送给特定用户。
    这里写图片描述
    我在文档文件里找cid列表格式,找了很就久,竟然没有找到。于是去骚扰度娘,她也不给里,找了半天也没有找到,接着找,终于在一个度娘的犄角旮旯里找到了。说每个cid占一行,多个cid之间用换行符号分开,文本文件。马上用文本编译器建立一个只含一个cid(从xcode的打印控制台日志里拷贝出来的)的列表,软后测试,还是推送不到。怀疑是文件格式不正确,转换成纯文本文件,再试还是不行。把cid后面加个换行符然后再测试,终于成功了。 个推cid列表文件
    遇到的问题7:iOS10及以后的推送操作新特性集成。iOS10及以后需要按照个推文档,增加一个NotificationService,Bundle Identifier要是主Target的Bundle Identifie(com.yixiang.agent)开头(com.yixiang.agent.NotificationService)。如怕有问题就按照我下图配置吧!然后按照个推文档增加对应的代码就可以。测试确实哪些新功能确实生效了。
    这里写图片描述
    这里写图片描述
    遇到的问题8:在测试环境测试完毕,一切OK。再次转战发布环境进行测试。结果落下一地的鸡毛。首先发布环境p12证书测试一直失败。
    这里写图片描述
    遇到问题按照我怀疑一切的个性。我怀疑:难道通过配置测试证书的app和正式证书的app,他们的token不同吗?经过打印token,发现在使用正式证书时,产生token确实不同,个推产生的cid也不同。我输入token正确然后测试生产p12证书还是不正确。看来问题和token有关,但是还有其他问题。我怀疑时p12证书有问题,我记得,我配置测试环境p12证书时是测试过了,配置生产环境证书时,我忘记是否测试过。
    这里写图片描述
    登录研发者账号,发现我的生产证书处于invalid状态(当时没有截图)。why?我的证书生成还不到半月,怎么是invalid状态呢?仔细想一想,我最近只进行了一次通过xcode同步一个ios8的手机配置(定位app打开外部链接在iOS9前后走的那个- (BOOL)application函数问题,以便于实现模块化开发。苹果的自动把设备加入研发测试手机列表),可能和那次操作有关。重新生成证书,再次测试生产环境的p12证书。这次终于apns证书测试通过了。
    遇到的问题9:按照个推文档,生产环境开发和测试环境需要分开测试。那么生产环境需要生用生产证书,当配置生产证书时,无法把应用直接安装到手机上,需要把ipa文件上传苹果商店,授权测试用户,用苹果的test flight软件下载测试,那样太麻烦了。那是否有更直接的方案呢?带有生产环境的证书性质,又可以安装到测试机上面呢?苹果还真有这种证书:
    这里写图片描述
    这里写图片描述
    虽然你要生成一个hot证书,并且不能联调,只能安装测试,和正式的生产证书有所不同,但是他们的功能已经很接近了,可以部分代替生产证书进行测试。注意:hot证书,生产证书,测试证书他们对应的token,cid都不相同。
    遇到的问题9:生产环境含有NotificationService的证书配置。推送测试环境,只需要把两个tartgets->General->Signing勾选 Automatically manage signing,电脑导入开发环境证书就可以测试了。然而生产环境要配置正确的证书,可没有这种傻瓜模式。只能去掉勾选Automatically manage signing。在Build Settings->Signing配置正确的证书。
    这里写图片描述
    如果你对Targets的NotificationService不配置证书或者配置和主Target的ArtEnjoymentWeChatAuction一样的发布证书会编译不过。经过咨询个推技术客户,他们说要对两个Bundle Identifie创建两个不同的证书。我经过紧张的证书制作。终于创建一个生产证书,一个hot证书在加上原来的测试证书,一个app共三个证书。
    这里写图片描述
    按照上面配置好证书终于不报错误了。可以愉快的玩耍了。
    遇到的问题10:既然主Target和NotificationService都有自己的生产证书,那么我们p12证书是使用的那个呢?
    这里写图片描述
    咨询个推客服,他说用com.yixiang.agent.NotificationService产生的证书。
    这里写图片描述
    这里写图片描述
    结果报一个新的错误:连接异常。
    买嘎,为什么受伤的总是我。反正这个问题是非正既反的问题,反着来试一试,ok,hot证书推送消息通过。呼唤服务器总部推送生产环境消息,测试pass。
    综合问题9和问题10,发现由com.yixiang.agent.NotificationService产生的证书表面看只是帮助编译通过,没有其它大用,真正个推应用配置的生产证书还是主Target的com.yixiang.agent产生的p12证书。
    一个支持个推推送的应用在研发者中心需要创建的证书有5个必须的证书和两个非必须的hot证书 :生产证书,测试环境证书,NotificationService证书 产生生产环境(包括 hot 证书)的p12证书的证书,产生测试环境的p12证书的证书,hot证书(非必须),NotificationService的hot证书(非必须)。
    遇到的问题11:上传苹果商店时报ERROR ITMS-90715错误。

    ERROR ITMS-90715: "Minimum OS too low. The Payload/ArtEnjoymentWeChatAuction.app/PlugIns/NotificationService.appex extension requires a version of iOS higher than the value specified for the MinimumOSVersion key in Info.plist."
    WARNING ITMS-90473: "CFBundleVersion Mismatch. The CFBundleVersion value '1.0.0' of extension 'ArtEnjoymentWeChatAuction.app/PlugIns/NotificationService.appex' does not match the CFBundleVersion value '1.0.3' of its containing iOS application 'ArtEnjoymentWeChatAuction.app'."
    WARNING ITMS-90473: "CFBundleShortVersionString Mismatch. The CFBundleShortVersionString value '1.0.0' of extension 'ArtEnjoymentWeChatAuction.app/PlugIns/NotificationService.appex' does not match the CFBundleShortVersionString value '1.0.3' of its containing iOS application 'ArtEnjoymentWeChatAuction.app'."
    

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    修改target的NotificationService版本号和target的ArtEnjoymentWeChatAuction版本号一致,然后打包上传就可以。报错如下:
    在这里插入图片描述

    ERROR ITMS-90715: "Minimum OS too low. The Payload/ArtEnjoymentWeChatAuction.app/PlugIns/NotificationService.appex extension requires a version of iOS higher than the value specified for the MinimumOSVersion key in Info.plist."
    

    在这里插入图片描述
    原来是Deployment Target版本支持的是8.0引起的。
    在这里插入图片描述
    这个是个推客服的回答。我删除Targets下的NotificationService重新打开工程打包上串苹果商店就可以了。
    注意:iOS8是iPhone 6安装的初始版本,现在市场上还有大量的iPhone 6手机,有的用户从来没有升级过苹果系统。升级操作系统是有风险的,我的iPhone 5s手机升级操作系统就遇到过升级成砖头了。我估计是手机空间不足引起的,也可能是一直提示验证系统我等不及了(5分钟左右)把手机重启了。幸亏我是搞app开发的,通过iTunes还原了系统,结果我所有的数据和应用都没有了,安装了两天app。
    遇到的问题12:当有应用在后台或没有启动,收到apns消息后,应用角标数字增加。无论是点击应用图标启动应用还是点击系统消息启动应用都不能清除角标。我们的应用还没有做消息列表页面,那如何清除角标呢?只有获取到 clientId(cid)后才能判断设置重置角标。我的做法是,应用启动是根据launchOptions是否为空来判断是否是点击系统消息启动应用,若非空(我们的apns消息的自定义键payload对应的值都可以解析出redirectUrl)就在获取到 clientId(cid)后重置角标。launchOptions的解析见添加链接描述《点击app系统消息打开app并进入指定页面》

    - (void)GeTuiSdkDidRegisterClient:(NSString *)clientId
    {
        FLDDLogDebug(@"函数 clientId:%@", clientId);
        if(!isEmptyString(clientId) && (!self.clientId || ![clientId isEqualToString:self.clientId]))
        {
            NSLog(@"clientId:%@", clientId);
            if(self.payloadFlag && !self.noFirstGetClientIdFlag)
            {
                [GeTuiSdk resetBadge]; //重置角标计数
                [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; // APP 清空角标
            }
            self.noFirstGetClientIdFlag = YES;
            self.payloadFlag = NO;
            [self submitWithUserInfo:@{@"clientId":clientId}];
        }
    }
    

    注意:由于应用每次从后台切换到前台都触发GeTuiSdkDidRegisterClient函数,所以要只第一获取到 clientId(cid)后才重置角标。
    来点干货,个推主代码如下,由于我们的app采用的是组件化,推送的代码在推送组件里处理,为了便于大家理解我把他移植到AppDelegate里以便于大家理解:
    AppDelegate.h

    #import <Foundation/Foundation.h>
    #import <GTSDK/GeTuiSdk.h>     // GetuiSdk头文件应用
    // iOS10 及以上需导入 UserNotifications.framework
    #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
    #import <UserNotifications/UserNotifications.h>
    #endif
    
    @interface AppDelegate : UIResponder<UIApplicationDelegate, GeTuiSdkDelegate, UNUserNotificationCenterDelegate>
    
    @end
    

    AppDelegate.m

    #import "AppDelegate.h"
    @interface AppDelegate ()<WXApiDelegate>
    
    @property (nonatomic, assign) BOOL isLaunch;
    @property (nonatomic, strong) NSString *clientId; //上传个推clientId,每次应用启动和从后台切换到前台应用都重新获取到clientId
    @property (nonatomic, strong) NSString *deviceToken; //上传个推deviceToken
    @property (nonatomic, assign) BOOL existCookieFlag; //存在cookie标志
    @property (nonatomic, assign) BOOL noFirstGetClientIdFlag; //每次应用从前台切换到后台就重新获取到ClientId,处理点击系统中的消息图标启动应用第一次获取到ClientId时重置角标
    @property (nonatomic, assign) BOOL payloadFlag; //标记点击系统中的消息图标启动应用,为YES时,第一次获取到ClientId时重置角标
    @end
    
    @implementation AppDelegate
    
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        FLDDLogVerbose(@"didFinishLaunchingWithOptions");
        // [EXT] 重新上线
        [GeTuiSdk startSdkWithAppId:kGeXinAppId appKey:kGeXinAppKey appSecret:kGeXinAppSecret delegate:self];
        // 注册 APNs
        [self registerRemoteNotification];
        // [2-EXT]: 获取启动时收到的APN
        NSDictionary* message = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
        
        FLDDLogVerbose(@"didFinishLaunchingWithOptions  message:%@,[message className]:%@", message, [message className]);
        if (message) {
    //        [AWSingleObject sharedInstance].redirectUrl = @"https://m.1-joy.com/market/cat/list.htm";
            NSString *payload = [message objectForKey:@"payload"];
            FLDDLogVerbose(@"payload:%@,[payload className]:%@", payload, [payload className]);
            if(payload)
            {
                self.payloadFlag = YES;
                NSData* jsondata = [payload dataUsingEncoding:NSUTF8StringEncoding];
                FLDDLogVerbose(@"jsondata:%@,[jsondata className]:%@", jsondata, [jsondata className]);
                NSError *error = nil;
                id jsonObject = [NSJSONSerialization JSONObjectWithData:jsondata options:NSJSONReadingAllowFragments error:&error];
                
                FLDDLogVerbose(@"jsonObject:%@,[jsonObject className]:%@,[jsonObject isKindOfClass:[NSDictionary class]]:%d, error:%@", jsonObject ,[jsonObject className], [jsonObject isKindOfClass:[NSDictionary class]], error);
                if(!error && jsonObject && [jsonObject isKindOfClass:[NSDictionary class]])
                {
                    NSString *redirectUrl = [jsonObject safeObjectForKey:@"redirectUrl"];
                    FLDDLogVerbose(@"redirectUrl:%@,[redirectUrl className]:%@", redirectUrl, [redirectUrl className]);
                    if(redirectUrl)
                    {
                        [AWSingleObject sharedInstance].redirectUrl = redirectUrl;
    //                    [[NSNotificationCenter defaultCenter] postNotificationName:@"redirectLoginNotification" object:nil userInfo:@{@"redirectUrl":@"http://getui.com\\"}];
                    }
                }
            }
    //        NSString *record = [NSString stringWithFormat:@"[APN]%@, %@", [NSDate date], payload];
            
            //如何跳转页面自己添加代码
            //
            //        self.window.rootViewController = self.viewController;
        }
        
        self.isLaunch = YES;
        return YES;
    }
    
    /** 注册 APNs */
    - (void)registerRemoteNotification {
        /*
         警告:Xcode8 需要手动开启"TARGETS -> Capabilities -> Push Notifications"
         */
        
        /*
         警告:该方法需要开发者自定义,以下代码根据 APP 支持的 iOS 系统不同,代码可以对应修改。
         以下为演示代码,注意根据实际需要修改,注意测试支持的 iOS 系统都能获取到 DeviceToken
         */
        if (@available(iOS 10.0, *)) {
    #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 // Xcode 8编译会调用
            UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
            center.delegate = self;
            [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionCarPlay) completionHandler:^(BOOL granted, NSError *_Nullable error) {
                if (!error) {
                    NSLog(@"request authorization succeeded!");
                }
            }];
            
            [[UIApplication sharedApplication] registerForRemoteNotifications];
    #else // Xcode 7编译会调用
            UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge);
            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
            [[UIApplication sharedApplication] registerForRemoteNotifications];
            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    #endif
        } else if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
            UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge);
            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
            [[UIApplication sharedApplication] registerForRemoteNotifications];
            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
        } else {
            UIRemoteNotificationType apn_type = (UIRemoteNotificationType)(UIRemoteNotificationTypeAlert |
                                                                           UIRemoteNotificationTypeSound |
                                                                           UIRemoteNotificationTypeBadge);
            [[UIApplication sharedApplication] registerForRemoteNotificationTypes:apn_type];
        }
    }
    
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
        NSLog(@"\nuserInfo:%@\n\n", userInfo);
        // 将收到的APNs信息传给个推统计
        [GeTuiSdk handleRemoteNotification:userInfo];
        completionHandler(UIBackgroundFetchResultNewData);
    }
    
    /** 远程通知注册成功委托 */
    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
        NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
        token = [token stringByReplacingOccurrencesOfString:@" " withString:@""];
        FLDDLogDebug(@"\n>>>[DeviceToken Success]:%@\n\n kGeXinAppId:%@", token, kGeXinAppId);
        if(isEmptyString(token))
        {
            return;
        }
    //    [[NSNotificationCenter defaultCenter] postNotificationName:@"submitNotification" object:nil userInfo:@{@"deviceToken":token}];
        [self submitWithUserInfo:@{@"deviceToken":token}];
        // 向个推服务器注册deviceToken
        [GeTuiSdk registerDeviceToken:token];
        NSString *clientId = [GeTuiSdk clientId];
        FLDDLogDebug(@"函数 clientId:%@", clientId);
        if(!isEmptyString(clientId))
        {
            NSLog(@"clientId:%@", clientId);
        }
        
    }
    
    #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
    
    //  iOS 10: App在前台获取到通知
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler  API_AVAILABLE(ios(10.0)){
        
        NSLog(@"willPresentNotification:%@", notification.request.content.userInfo);
        
        // 根据APP需要,判断是否要提示用户Badge、Sound、Alert
        if (@available(iOS 10.0, *)) {
            completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert);
        } else {
            // Fallback on earlier versions
        }
    }
    
    //  iOS 10: 点击通知进入App时触发,在该方法内统计有效用户点击数
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler  API_AVAILABLE(ios(10.0)){
        
        NSLog(@"didReceiveNotification:%@", response.notification.request.content.userInfo);
        
        [GeTuiSdk resetBadge]; //重置角标计数
        [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; // APP 清空角标
    
        // [ GTSdk ]:将收到的APNs信息传给个推统计
        [GeTuiSdk handleRemoteNotification:response.notification.request.content.userInfo];
        
        completionHandler();
    }
    
    #endif
    
    
    #pragma mark - GexinSdkDelegate
    - (void)GexinSdkDidOccurError:(NSError *)error
    {
        // [EXT]:个推错误报告,集成步骤发生的任何错误都在这里通知,如果集成后,无法正常收到消息,查看这里的通知。
        NSLog(@">>>[GexinSdk error]:%@", [error localizedDescription]);
    }
    
    /** SDK收到透传消息回调 */
    - (void)GeTuiSdkDidReceivePayloadData:(NSData *)payloadData andTaskId:(NSString *)taskId andMsgId:(NSString *)msgId andOffLine:(BOOL)offLine fromGtAppId:(NSString *)appId {
        //收到个推消息
        NSString *payloadMsg = nil;
        if ((payloadData) && ([payloadData isKindOfClass:[NSData class]])) {
            payloadMsg = [[NSString alloc] initWithBytes:payloadData.bytes length:payloadData.length encoding:NSUTF8StringEncoding];
            
    //        NSData* jsondata = [payload dataUsingEncoding:NSUTF8StringEncoding];
            FLDDLogVerbose(@"payloadData:%@,[payloadData className]:%@", payloadData, [payloadData className]);
            NSError *error = nil;
            id jsonObject = [NSJSONSerialization JSONObjectWithData:payloadData options:NSJSONReadingAllowFragments error:&error];
            
            FLDDLogVerbose(@"jsonObject:%@,[jsonObject className]:%@,[jsonObject isKindOfClass:[NSDictionary class]]:%d, error:%@", jsonObject ,[jsonObject className], [jsonObject isKindOfClass:[NSDictionary class]], error);
            if(!error && jsonObject && [jsonObject isKindOfClass:[NSDictionary class]])
            {
                NSString *redirectUrl = [jsonObject safeObjectForKey:@"redirectUrl"];
                NSString *title = [jsonObject safeObjectForKey:@"title"];
                NSString *body = [jsonObject safeObjectForKey:@"body"];
                FLDDLogVerbose(@"redirectUrl:%@,[redirectUrl className]:%@", redirectUrl, [redirectUrl className]);
                if((title && [title isKindOfClass:[NSString class]]) || (body && [body isKindOfClass:[NSString class]]))
                {
                    redirectUrl = isEmptyString(redirectUrl) ? @"" : redirectUrl;
                    title = isEmptyString(title) ? @"" : title;
                    body = isEmptyString(body) ? @"" : body;
                    UILocalNotification *notification = [[UILocalNotification alloc] init];
                    if (notification != nil) {
                        // 设置推送时间
                        notification.fireDate = [NSDate date];
                        // 设置时区
                        notification.timeZone = [NSTimeZone defaultTimeZone];
                        // 设置重复间隔
                        notification.repeatInterval = 0;
                        // 推送声音
                        notification.soundName = UILocalNotificationDefaultSoundName;
                        if (@available(iOS 8.2, *)) {
                            notification.alertTitle = title;
                        } else {
                            // Fallback on earlier versions
                        }
                        // 推送内容
                        notification.alertBody = body;
                        notification.userInfo = jsonObject;
                        notification.category = payloadMsg;
                        //显示在icon上的红色圈中的数子
                        notification.applicationIconBadgeNumber =0;
                        //添加推送到UIApplication
                        UIApplication *app = [UIApplication sharedApplication];
                        [app scheduleLocalNotification:notification];
                    }
                }
            }
        }
        
        NSString *msg = [NSString stringWithFormat:@"taskId=%@,messageId:%@,payloadMsg:%@%@",taskId,msgId, payloadMsg,offLine ? @"<离线消息>" : @""];
        NSLog(@"\n>>>[GexinSdk ReceivePayload]:%@\n\n", msg);
    }
    
    /**
     *  SDK登入成功返回clientId
     *
     *  @param clientId 标识用户的clientId
     *  说明:启动GeTuiSdk后,SDK会自动向个推服务器注册SDK,当成功注册时,SDK通知应用注册成功。
     *  注意: 注册成功仅表示推送通道建立,如果appid/appkey/appSecret等验证不通过,依然无法接收到推送消息,请确保验证信息正确。
     */
    - (void)GeTuiSdkDidRegisterClient:(NSString *)clientId
    {
        FLDDLogDebug(@"函数 clientId:%@", clientId);
        if(!isEmptyString(clientId) && (!self.clientId || ![clientId isEqualToString:self.clientId]))
        {
            NSLog(@"clientId:%@", clientId);
            //        [GeTuiSdk bindAlias:@"y790715966c94d93e84182fbfce36182123456GS" andSequenceNum:@"1sssas2223446"];
            if(self.payloadFlag && !self.noFirstGetClientIdFlag)
            {
                [GeTuiSdk resetBadge]; //重置角标计数
                [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; // APP 清空角标
            }
            self.noFirstGetClientIdFlag = YES;
            self.payloadFlag = NO;
            
    //        [GeTuiSdk resetBadge]; //重置角标计数
    //        [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; // APP 清空角标
            
    //        [[NSNotificationCenter defaultCenter] postNotificationName:@"submitNotification" object:nil userInfo:@{@"clientId":clientId}];
            [self submitWithUserInfo:@{@"clientId":clientId}];
        }
    }
    
    /**
     *  SDK运行状态通知
     *
     *  @param aStatus 返回SDK运行状态
     */
    - (void)GeTuiSDkDidNotifySdkState:(SdkStatus)aStatus;
    {
        FLDDLogDebug(@"aStatus:%d", aStatus);
    }
    /**
     *  SDK设置关闭推送模式回调
     *
     *  @param isModeOff 关闭模式,YES.服务器关闭推送功能 NO.服务器开启推送功能
     *  @param error     错误回调,返回设置时的错误信息
     */
    - (void)GeTuiSdkDidSetPushMode:(BOOL)isModeOff error:(NSError *)error;
    {
        FLDDLogDebug(@"isModeOff:%d, error:%@", isModeOff, error);
    }
    /**
     *  SDK绑定、解绑回调
     *
     *  @param action       回调动作类型 kGtResponseBindType 或 kGtResponseUnBindType
     *  @param isSuccess    成功返回 YES, 失败返回 NO
     *  @param aSn          返回请求的序列码
     *  @param aError       成功返回nil, 错误返回相应error信息
     */
    - (void)GeTuiSdkDidAliasAction:(NSString *)action result:(BOOL)isSuccess sequenceNum:(NSString *)aSn error:(NSError *)aError;
    {
        FLDDLogDebug(@"action:%@, isSuccess:%d, aSn:%@, aError:%@", action, isSuccess, aSn, aError);
    }
    
    -(void)submit:(NSNotification *)notification
    {
        NSDictionary* userInfo = [notification userInfo];
        [self submitWithUserInfo:userInfo];
    }
    
    -(void)submitWithUserInfo:(NSDictionary *)userInfo
    {
        NSLog(@"userInfo:%@", userInfo);
        NSString *existCookieFlag = [userInfo objectForKey:@"existCookieFlag"];
        if(!isEmptyString(existCookieFlag))
        {
            if([existCookieFlag isEqualToString:@"YES"])
            {
                self.existCookieFlag = YES;
            }
            else
            {
                self.existCookieFlag = NO;
            }
        }
        NSString *deviceToken = [userInfo objectForKey:@"deviceToken"];
        if(!isEmptyString(deviceToken))
        {
            self.deviceToken = deviceToken;
        }
        NSString *clientId = [userInfo objectForKey:@"clientId"];
        if(!isEmptyString(clientId))
        {
            self.clientId = clientId;
        }
        
        if(isEmptyString(self.clientId ) || !(self.existCookieFlag))
        {
            return;
        }
        
        NSString *urlStr = [NSString stringWithFormat:@"%@getui/dd.htm?appId=%@&type=ios",  kBaseURL, kGeXinAppId];
        if(!isEmptyString(self.clientId))
        {
            urlStr = [NSString stringWithFormat:@"%@&clientId=%@", urlStr, self.clientId];
        }
        if(!isEmptyString(self.deviceToken))
        {
            urlStr = [NSString stringWithFormat:@"%@&deviceToke=%@", urlStr, self.deviceToken];
        }
        urlStr = [urlStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];//编码
        NSLog(@"urlStr:%@", urlStr);
        NSURL * url = [NSURL URLWithString:urlStr];
        NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
        NSURLSession * session = [NSURLSession sharedSession];
        NSString *cookie = [self readCurrentCookieWithDomain:urlStr];
        [request addValue:cookie forHTTPHeaderField:@"Cookie"];
        // 发送请求
        NSURLSessionTask * sessionTask = [session dataTaskWithRequest:request
                                                    completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                        if (error) {
                                                            return;
                                                        }
                                                        NSString *mmmmmmm = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                                                        NSLog(@"urlStr:%@ error:%@, request.allHTTPHeaderFields:%@", urlStr, error, request.allHTTPHeaderFields);
                                                        NSLog(@"mmmmmmm: %@, response:%@", mmmmmmm, response);
                                                    }];
        [sessionTask resume];
    }
    
    - (NSString *)readCurrentCookieWithDomain:(NSString *)domainStr{
        NSHTTPCookieStorage*cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
        NSMutableString * cookieString = [[NSMutableString alloc]init];
        for (NSHTTPCookie*cookie in [cookieJar cookies]) {
            [cookieString appendFormat:@"%@=%@;",cookie.name,cookie.value];
        }
        
        //删除最后一个“;”
        [cookieString deleteCharactersInRange:NSMakeRange(cookieString.length - 1, 1)];
        return cookieString;
    }
    
    - (void)applicationDidEnterBackground:(UIApplication *)application
    {
        self.isLaunch = NO;
    }
    
    - (void)applicationDidBecomeActive:(UIApplication *)application
    {
        if (self.isLaunch) {
            return;
        }
    }
    
    - (void)dealloc
    {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
    
    
    @end
    
    展开全文
  • 个推推送模板详解

    千次阅读 2019-12-23 18:04:42
    作为专业的消息推送服务商,个推为开发者提供了不同种类的推送模板,以实现相应的推送功能。推送模板可以单用,也可以组合使用。为帮助APP开发者更快速地找到适合的推送模板,实现所想要的推送效果,我们写下这篇...

    背景

    作为专业的消息推送服务商,个推为开发者提供了不同种类的推送模板,以实现相应的推送功能。推送模板可以单用,也可以组合使用。为帮助APP开发者更快速地找到适合的推送模板,实现所想要的推送效果,我们写下这篇教学普及贴,希望可以帮到大家。

     

    推送样式

    个推提供了不同的推送样式,比如系统样式展开式通知样式

    ps. setLogo的图片需要在客户端开发时嵌入(main-res),否则无法展示;

    pps. setLogo 和 setLogoUrl 可以二选一。如果二者都设置了,则 setLogoUrl 优先级比setLogo高,但是小米、华为等有些机型并不支持该功能,因此,开发者要慎选;

     ppps. small logo图片没有可以修改的服务端接口,展示客户端内置的图片,默认值是push_small.png,很多手机(比如小米)改过其展示效果,这部分的小图标不一定能显示出来;

     

    系统样式展开式通知样式具体代码如下:

           //系统样式
         public static AbstractNotifyStyle getStyle0() {
            Style0 style = new Style0();
            style.setTitle("这是你想要的标题");
            style.setText("这是你想要的内容");
            style.setLogo("push.png");//配置通知栏图标,需要在客户端开发时嵌入
            style.setLogoUrl("");//配置通知栏网络图标
            style.setRing(true); //设置通知是否响铃
            style.setVibrate(true); //设置通知是否震动
            style.setClearable(true); //设置通知是否可清除
            //Android 8.0 以上支持的
            style.setChannel("通知渠道id");
            style.setChannelName("通知渠道名称");
            style.setChannelLevel(3);
            return style;
        }
       
        //展开式通知样式
         public static AbstractNotifyStyle getStyle6() {
            Style6 style = new Style6();
            style.setTitle("这是你想要的标题");
            style.setText("这是你想要的内容");
            style.setLogo("push.png"); //配置通知栏图标,需要在客户端开发时嵌入
            style.setLogoUrl(""); //配置通知栏网络图标
            // 两种方式选一种
            style.setBigStyle1("bigImageUrl"); //设置大图+文本样式
                  //style.setBigStyle2("bigText"); //设置长文本+文本样式
            style.setRing(true);
            style.setVibrate(true);
            style.setClearable(true);
            style.setChannel("通知渠道id");
            style.setChannelName("通知渠道名称");
            style.setChannelLevel(3);
            return style;
        }

    效果图

     以小米8手机 Android 9版本为例,推送效果如下(为了脱敏,直接用个推demo自带的图标)

     

    上述代码中提到了安卓8.0系统中开始支持的通知渠道,具体的字段含义解释如下。

    setChannel表示通知渠道id,是渠道的唯一标识,其默认值为“Default”  ;setChannelName表示通知渠道名称,用户可在手机“设置”中查看,其默认值也为“Default”。  setChannelName长度建议设置在40Byte以内,超出会被安卓8.0系统自动缩减。  setChannelLevel表示设置通知渠道的重要性,其默认值为3。具体操作过程中值有五种可供选择:0、1、2、3、4;设置之后不能修改,展示形式如下:

    0:无声音,无震动,不显示。

    1:无声音,无震动,锁屏不显示,通知栏中内容被折叠显示,导航栏无logo。

     2:无声音,无震动,锁屏和通知栏都予以显示,通知不唤醒屏幕。

     3:有声音,有震动,锁屏和通知栏中都予以显示,通知唤醒屏幕。

     4:有声音,有震动,亮屏下通知悬浮展示,锁屏通知以默认形式展示且唤醒屏幕。

    ppps. channel设置完后,就不能再对channelLevel进行修改,只能新建一个新的channel。这是安卓原生的限制;

     

     

    推送模板

    到此,大家应该已经了解了想要推送的展示效果,但是需要什么样的模板来实现具体的通知效果呢?各位请继续往下看。

     

    通知 & 启动应用

    采用下述代码用户可以在通知栏看到一条含图标、标题等的通知,当他点击后可以激活应用,到达应用首页。

            NotificationTemplate template = new NotificationTemplate();
            template.setAppId(APPID);
            template.setAppkey(APPKEY);
            template.setStyle(getStyle0()); //设置展示样式,具体见推送样式部分

     

    通知 &启动应用 & 透传

    这种方式在前一种的基础上,加了透传(这部分内容用户是看不到的)。通过透传可以达到不同的效果,比如更新用户信息。

            NotificationTemplate template = new NotificationTemplate();
            template.setAppId(APPID);
            template.setAppkey(APPKEY);
            template.setStyle(getStyle0());
            template.setTransmissionType(1); // 透传消息设置;1:立即启动APP;2:客户端收到消息后需要自行处理
            template.setTransmissionContent("透传内容");
           

     

    通知 & 打开网页

    下述代码用户可以在通知栏看到一条含图标、标题等的通知。当他点击通知、启动手机浏览器,便可以打开该通知所设置好的页面。

            LinkTemplate template = new LinkTemplate();
            template.setAppId(APPID);
            template.setAppkey(APPKEY);
            template.setStyle(getStyle0());
            template.setUrl("http://www.baidu.com");  //设置打开的网址地址

     

    通知 & 启动应用打开intent

    这是我们最常见的方方式:点击通知,打开APP内指定的页面。

            StartActivityTemplate template = new StartActivityTemplate();
            template.setAppId(APPID);
            template.setAppkey(APPKEY);
            template.setStyle(getStyle0());
            String intent = "intent:#Intent;component=com.yourpackage/.NewsActivity;end";//这部分写法不清楚的,可以咨询安卓客户端的童鞋
            template.setIntent(intent); //最大长度限制为1000,很重要

     

    透传

    如果大家有一些个性化需求,比如想要自己定义所要实现的展示效果,那么可以用纯透传的方式。

            TransmissionTemplate template = new TransmissionTemplate();
            template.setAppId(APPID);
            template.setAppkey(APPKEY);
            template.setTransmissionType(2);// // 透传消息设置;1:立即启动APP;2:客户端收到消息后需要自行处理,如果设置为1,对用户使用不友好,不推荐使用
            template.setTransmissionContent("透传内容");

     

    消息撤回

    这个功能很实用,当App运营者不小心发送了不当的消息,可以立马撤回。

            RevokeTemplate template = new RevokeTemplate();
            template.setAppId(APPID);
            template.setAppkey(APPKEY);
            template.setOldTaskId(taskId); //指定需要撤回消息对应的taskId
            template.setForce(false); //客户端没有找到对应的taskid,是否把对应appid下所有的通知都撤回

     

    消息覆盖

    比如足球比赛实时比分播报,用户只想知道最新比分,我们就可以选择“消息覆盖”方式的推送模板。

    前面代码中提到的StartActivityTemplateLinkTemplateNotificationTemplate 都有一个方法:setNotifyid(Integer notifyid)。在消息推送的时候设置notifyid,当有覆盖需求时,使用相同的notifyid发一条新的消息,客户端sdk会根据notifyid对应的前一条消息进行覆盖。

     

    iOS推送

    你可能发现了前面所讲的都是基于安卓推送的操作, iOS的操作相对会比较特殊。逻辑是当APP在线时,个推消息推送会直接把透传内容发送到手机上,需要客户端解析后予以展示;当APP离线时,推送会采用APNs通道,由iPhone的系统通道通知并展示消息。iOS推送可以采用TransmissionTemplate模板,根据setAPNInfo(Payload apn)法来设置具体参数。

    具体参数基本上按照iOS官网的字段来进行命名,应该会比较容易上手。这里附上iOS官网文档链接。

    个推iOS推送参考代码如下:

    private static APNPayload getAPNPayload() {
            APNPayload payload = new APNPayload();
            //在已有数字基础上加1显示,设置为-1时,在已有数字上减1显示,设置为数字时,显示指定数字
            payload.setAutoBadge("+1");
            payload.setContentAvailable(1);
            //ios 12.0 以上可以使用 Dictionary 类型的 sound
            payload.setSound("default");
            payload.setCategory("$由客户端定义种类");
            payload.addCustomMsg("由客户自定义消息key", "由客户自定义消息value");

            payload.setAlertMsg(getDictionaryAlertMsg());  //字典模式

            //设置语音播报类型,int类型,0.不可用 1.播放body 2.播放自定义文本
            payload.setVoicePlayType(2);
            //设置语音播报内容,String类型,非必须参数,用户自定义播放内容,仅在voicePlayMessage=2时生效
            //注:当"定义类型"=2, "定义内容"为空时则忽略不播放
            payload.setVoicePlayMessage("定义内容");

            //添加多媒体资源,可以是图片、音频、视频,最多可以添加3条多媒体
            payload.addMultiMedia(new MultiMedia().setResType(MultiMedia.MediaType.pic)
                    .setResUrl("资源文件地址")
                    .setOnlyWifi(true));//设置是否在WIFI下才展示多媒体消息,如果设置true但未使用WIFI时会展示成普通通知

            return payload;
        }

     private static APNPayload.DictionaryAlertMsg getDictionaryAlertMsg() {
            APNPayload.DictionaryAlertMsg alertMsg = new APNPayload.DictionaryAlertMsg();
            alertMsg.setBody("body1");
            alertMsg.setActionLocKey("显示关闭和查看两个按钮的消息");
            alertMsg.setLocKey("loc-key1");
            alertMsg.addLocArg("loc-ary1");
            alertMsg.setLaunchImage("调用已经在应用程序中绑定的图形文件名");
            alertMsg.setTitle("通知标题");
            alertMsg.setTitleLocKey("自定义通知标题");
            alertMsg.addTitleLocArg("自定义通知标题组");
            return alertMsg;
        }

        /**
         * 需要使用iOS语音传输,请使用VoIPPayload代替APNPayload
         * 需要相关证书才可以使用此功能
         */
        private static VoIPPayload getVoIPPayload() {
            VoIPPayload payload = new VoIPPayload();
            JSONObject jo = new JSONObject();
            jo.put("key1", "value1");
            payload.setVoIPPayload(jo.toString());
            return payload;
        }

     

    总结

    个推推送模板提供了系统样式和展开通知样式,但是开发者请务必要注意:Android和iOS的代码推送方式是不同的。推送iOS消息,只能用TransmissionTemplate透传模板;推送Android消息,可以使用TransmissionTemplate透传模板和NotificationTemplate、LinkTemplate、StartActivityTemplate、RevokeTemplate通知类模板。为提供更优质的推送服务,个推持续优化产品功能,丰富推送模板,同时将于近期推出基于Restful的v2接口,以更加符合开发者的使用习惯,敬请期待。

     

     

    展开全文
  • 个推 - 消息推送

    千次阅读 2018-09-14 10:40:21
    最近研究了一下个推的消息推送,记录一下。

    绪论

    最近研究了一下个推的消息推送,记录一下。
    首先引入5个jar包。
    这里写图片描述

    使用个推官网演示应用
    这里写图片描述

    主要代码
    import com.gexin.rp.sdk.base.IPushResult;
    import com.gexin.rp.sdk.base.impl.SingleMessage;
    import com.gexin.rp.sdk.base.impl.Target;
    import com.gexin.rp.sdk.base.payload.APNPayload;
    import com.gexin.rp.sdk.exceptions.RequestException;
    import com.gexin.rp.sdk.http.IGtPush;
    import com.gexin.rp.sdk.template.NotificationTemplate;
    import com.gexin.rp.sdk.template.TransmissionTemplate;
    import com.gexin.rp.sdk.template.style.Style0;
    
    public class PushMsg {
    	static PushMsg me = new PushMsg();
    	static String appId = "VoT36u3tds8M15ppeP7HG9";
        static String appKey = "oRVwYdcvSv9Bi5Ux9QJ3I6";
        static String masterSecret = "x0dk6oYZ2i7S99l1FEvBr8";
        static String clientId = "95ac79fe19b25f37cd6b087cfaf8e79f";
        // 个推接口地址
        static String host = "http://sdk.open.api.igexin.com/apiex.htm";
        
        /**
         * 消息通知
         */
        private NotificationTemplate setTongZhi(){
        	// 在通知栏显示一条含图标、标题等的通知,用户点击后激活您的应用
            NotificationTemplate template = new NotificationTemplate();
            // 设置appid,appkey
            template.setAppId(appId);
            template.setAppkey(appKey);
            // 穿透消息设置为,1 强制启动应用
            template.setTransmissionType(1);
            // 设置穿透内容
            template.setTransmissionContent("我是普通消息通知1");
            // 设置style
            Style0 style = new Style0();
            // 设置通知栏标题和内容
            style.setTitle("推送提醒");
            style.setText("我是普通消息通知2");
            // 设置通知,响铃、震动、可清除
            style.setRing(true);
            style.setVibrate(true);
            style.setClearable(true);
            // 设置
            template.setStyle(style);
            return template;
        }
        
        /**
         * 消息透传
         */
        private TransmissionTemplate setTouChuan(){
            TransmissionTemplate template = new TransmissionTemplate();
            template.setAppId(appId);
            template.setAppkey(appKey);
            template.setTransmissionContent("我是透传信息1");
            template.setTransmissionType(2);
            APNPayload payload = new APNPayload();
            //在已有数字基础上加1显示,设置为-1时,在已有数字上减1显示,设置为数字时,显示指定数字
            payload.setAutoBadge("+1");
            payload.setContentAvailable(1);
            payload.setSound("default");
            payload.setAlertMsg(getDictionaryAlertMsg());
            template.setAPNInfo(payload);
            return template;
        }
        
        /**
         *  消息设置
         */
        private APNPayload.DictionaryAlertMsg getDictionaryAlertMsg() {
            APNPayload.DictionaryAlertMsg alertMsg = new APNPayload.DictionaryAlertMsg();
            alertMsg.setTitle("透传提醒");
            alertMsg.setBody("我是透传信息2");
            return alertMsg;
        }
        
        /* 对单个用户推送消息
    	 * 1. clientId
    	 * 2. 要传到客户端的 msg
    	 * 2.1 标题栏:key = title,
    	 * 2.2 通知栏内容: key = titleText,
    	 * 2.3 穿透内容:key = transText
    	 */
        public String pushTongZhi() {
            // 代表在个推注册的一个 app,调用该类实例的方法来执行对个推的请求
            IGtPush push = new IGtPush(host, appKey, masterSecret);
            // 创建信息模板
            NotificationTemplate template = setTongZhi();
            //定义消息推送方式为,单推
            SingleMessage message = new SingleMessage();
            // 设置推送消息的内容
            message.setData(template);
            message.setOffline(true);
            // 离线有效时间,单位为毫秒,可选
            message.setOfflineExpireTime(24 * 3600 * 1000);
            // 可选,1为wifi,0为不限制网络环境。根据手机处于的网络情况,决定是否下发
            message.setPushNetWorkType(0);
            // 设置推送目标
            Target target = new Target();
            target.setAppId(appId);
            // 设置clientId
            target.setClientId(clientId);
    
            // 获得推送结果
            IPushResult ret = null;
            try {
                ret = push.pushMessageToSingle(message, target);
            } catch (RequestException e) {
                e.printStackTrace();
                ret = push.pushMessageToSingle(message, target, e.getRequestId());
            }
            if (ret != null) {
                System.out.println(ret.getResponse().toString());
            } else {
                System.out.println("服务器响应异常");
            }
            /* 1. 失败:{result=sign_error}
             * 2. 成功:{result=ok, taskId=OSS-0212_1b7578259b74972b2bba556bb12a9f9a, status=successed_online}
             * 3. 异常
             */
            System.out.println("通知发送结果:" + ret.getResponse().toString());
            return ret.getResponse().toString();
        }
    
        /* 对单个用户推送消息
    	 * 1. clientId
    	 * 2. 要传到客户端的 msg
    	 * 2.1 标题栏:key = title,
    	 * 2.2 通知栏内容: key = titleText,
    	 * 2.3 穿透内容:key = transText
    	 */
        public String pushTouChuan() {
            // 代表在个推注册的一个 app,调用该类实例的方法来执行对个推的请求
            IGtPush push = new IGtPush(host, appKey, masterSecret);
            // 创建信息模板
            TransmissionTemplate template = setTouChuan();
            //定义消息推送方式为,单推
            SingleMessage message = new SingleMessage();
            // 设置推送消息的内容
            message.setData(template);
            message.setOffline(true);
            // 离线有效时间,单位为毫秒,可选
            message.setOfflineExpireTime(24 * 3600 * 1000);
            // 可选,1为wifi,0为不限制网络环境。根据手机处于的网络情况,决定是否下发
            message.setPushNetWorkType(0);
            // 设置推送目标
            Target target = new Target();
            target.setAppId(appId);
            // 设置clientId
            target.setClientId(clientId);
    
            // 获得推送结果
            IPushResult ret = null;
            try {
                ret = push.pushMessageToSingle(message, target);
            } catch (RequestException e) {
                e.printStackTrace();
                ret = push.pushMessageToSingle(message, target, e.getRequestId());
            }
            if (ret != null) {
                System.out.println(ret.getResponse().toString());
            } else {
                System.out.println("服务器响应异常");
            }
            /* 1. 失败:{result=sign_error}
             * 2. 成功:{result=ok, taskId=OSS-0212_1b7578259b74972b2bba556bb12a9f9a, status=successed_online}
             * 3. 异常
             */
            System.out.println("透传发送结果:" + ret.getResponse().toString());
            return ret.getResponse().toString();
        }
    }
    
    
    调用一下
    public class Main {
    	public static void main(String[] args) {
    		PushMsg.me.pushTongZhi();
    		//PushMsg.me.pushTouChuan();
    	}
    }
    

    通知发送结果:{result=ok, taskId=OSS-0914_480d2dab12f91e6e0ef2bc401f7406b8, status=successed_online}
    这里写图片描述

    透传发送结果:{result=ok, taskId=OSS-0914_cb373c43f5b1fc73c63509b67a8e27c5, status=successed_online}
    这里写图片描述

    这样就可以看出我们发送的消息会显示那个在哪里,从而设置好数据格式,展示具体信息。

    (若有什么错误,请留言指正,3Q)

    展开全文
  • Android 消息推送:个推

    万次阅读 2018-01-30 13:49:09
    之前一直在使用极光推送,这次项目打算使用个推试试!个推个推官方文档集成失败原因:1、检查自己的APPID等信息2、检查AndroidManifest.xml&lt;!-- 自定义权限 自定义权限解释:部分手机型号不能正常运行个推...
  • unipush+java+个推实现app消息推送

    千次阅读 热门讨论 2020-08-26 11:09:15
    对于安卓,谷歌本来有专门的推送通道,但是无奈被墙,所以各个大厂就自己各搞一套,那我们开发者如果每个都去开发一套成本就太高了,所以就需要借助第三方通道,让他们帮我们处理,目前比较火的有个推,极光等等,...
  • Java集成个推实现简单推送服务

    千次阅读 2020-04-17 12:37:48
    Java集成个推简单推送 1、注册个推账号创建应用。 个推注册地址 2、服务端集成文档地址 3、集成方式 方法一:maven方式安装 将下边的依赖放到maven项目的 pom.xml 中: <dependency> <groupId>...
  • vue消息推送【个推

    千次阅读 2019-04-30 14:20:34
    由于个推在市场上使用量比较多,于是就开启了我的Vue消息推送个推之旅。 而此时发现个推的开发者中心注册账号时,需要: 这些他必须要得提供。我们知道android包名和IOS bundleID就是我们使用Hbuilder的包名,...
  • Hbuilder+Mui+个推实现移动端消息推送

    万次阅读 2018-06-06 09:50:48
    注册个推账号 http://www.getui.com//cn/index.html在个推官网注册个推账号登记应用获取webapp的appid,如上图保存后如下图:App端改造移动端登陆后,需要缓存移动端clientId信息,如下:/** * 缓存处理用户...
  • APP消息推送-个推java端实现

    千次阅读 2019-01-13 11:25:00
    -- 个推sdk的依赖 --&amp;amp;gt; &amp;amp;lt;dependency&amp;amp;gt; &amp;amp;lt;groupId&amp;amp;gt;com.gexin.platform&amp;amp;lt;/groupId&amp;amp;gt; &amp;amp;lt;...
  • 个推消息推送iOS版常见问题整理

    千次阅读 2019-09-05 14:31:29
    为了更好地服务开发者,此次我们针对个推消息推送iOS版使用中可能出现的一些常见问题做了整理,提供了一些比较方便掌握的解决方法,希望能帮助到大家。 1. iOS推送流程是什么样的? iOS下发的消息分两部分:一部分...
  • 个推消息推送Android版常见问题整理

    千次阅读 2019-09-05 14:37:19
    为了更好地服务开发者,此次我们针对个推Android推送使用中可能出现的一些常见问题做了整理,提供了一些比较方便掌握的解决方法,希望能帮助到大家。 1. Android推送和iOS推送调用模板的区别? Android调用推送模板...
  • 详解个推java服务端集成(干货)

    千次阅读 2019-03-30 11:44:05
    个推是商用级的移动应用消息推送云服务解决方案,客户端SDK支持Android和iOS两大平台,云端支持丰富的网页端推送管理功能和多种语言版本的API开放接口。 第三方应用开发者可以借助该服务,快速构建...
  • Android 推送-个推

    千次阅读 2016-12-22 18:56:16
    最近闲来无事就把个推研究了一下,发现个推的SDK版本已经更新到2.9.5.0了,而且跟以前的版本相比感觉变化实在是太大了。 以前的版本在配置清单里面的配置为<!-- 配置第三方Receiver--> android:name=...
  • 个推+mui+html5 +java完成消息推送

    千次阅读 2018-07-11 17:07:02
    几个月前写的,个推官方的例子真是难,找了好久才拼出来这几个方法,本文包含java调用个推SDK的消息推送和app方向的接收消息。package geti; import java.io.IOException; import java.util.ArrayList; import java....
  • 消息推送(个推

    千次阅读 2017-12-08 17:31:29
    1.总得先说两句 ...推送:个推(透传消息) 通知:自定义Notification 2.1 先来创建个推账户吧 个推官网,个人账户和公司账户均可。 2.2 个推开发者中心 1.登记应用 2.填写项目...
  • 个推App消息推送

    万次阅读 2017-09-07 09:27:57
    个推 消息推送的研究经历 注意:登记时的应用标识就是appid. 应用登记成功之后会得到APPID,APPSecret,APPkey,MasterSecret 接着就需要配置sdk了,把得到的数值填入相对应的名字里面就可以了 这些做完...
  • c#,利用个推实现APP消息推送

    千次阅读 2018-01-24 11:23:56
    * GetuiServerApiSDK:此.dll文件为个推C#版本的SDK文件 * Google.ProtocolBuffers:此.dll文件为Google的数据交换格式文件 * 注: * 新增一个连接超时时间设置,通过在环境变量--用户变量中增加名为:GETUI_...
  • android个推

    千次阅读 2017-05-20 11:14:30
    之前公司用的推送是极光,昨天公司要求转战个推,然后查看了个推的开发文档,可以说非常简单。缺点就是通知需要我们android客户端本地发送。后面会详细说。 个推的集成文档:...
  • 个推和极光推送技术介绍

    万次阅读 2015-09-10 12:54:44
     在移动互联网以前的手机,如果有事情发生要通知用户,则会弹出一窗口,告诉用户正在发生的事,可能是未接电话提示、日历提醒或是一封彩信。送功能最早是被用于Email中,而目前更多地被应用于App中。   2、...
  • 小米推送,华为推送,个推,阿里云推送集成(服务端JAVA开发)
  • hbuilder的个推使用问题总结

    千次阅读 2018-09-04 14:15:15
    Hubilder ios推送使用个推总结 首先根据hbuilder的官方知道进行配置开发是没有任何问题的 对于ios的应用在线情况下:推送走的是个推平台和应用个推SDK的TCP长链接,在监听了receiver方法页面中可以收到透传消息。...
  • 由于项目开发需要,需要服务端推送数据到安卓客户端,最终选择了第三方的个推数据推送。准备工作个推官网有详细介绍,此处不做详解。基本推算原理:在个推注册绑定客户端后,每一个客户端会有一个唯一的客户端id,...
  • iOS集成个推推送

    千次阅读 2017-07-03 11:54:31
    前段时间由于项目需要,要使用个推进行推送,由于以前主要接触的是极光推送,所以集成过程中出现了很多问题,以防以后再次出现同样的问题,特意记录一下,也希望能帮到需要的人。 首先看一下个推官网提供的推送流程...
  • 利用MUI+个推实现APP消息推送

    万次阅读 2016-09-12 19:43:22
    利用MUI+个推实现APP消息推送从2015年7月开始使用MUI进行APP的开发,到现在已经有一个年头了。而以前做过的东西都没有整理过,以后会将自己遇到的坑整理下来。 这篇主要是讲利用MUI和集成的个推来实现APP的消息推送...
  • 个推实例详解-java

    千次阅读 2017-02-08 11:58:32
    个推官网直接推送 1,在个推官网注册个账号 注册地址:https://dev.getui.com/dos4.0/index.html#register 注册完进入配置页面,对应用进行配置,框中的几个地方接下来要用到,应用名称一定要跟开发的应用名称一致 ...
  • 个推推送步骤

    千次阅读 2016-06-24 16:43:28
    第一步:导入个推SDK 将SDK资料包中“GETUI_ANDROID_SDK\资源文件”目录下的GetuiSdk-xxx.jar、so文件夹子文件复制到app模块目录下的libs文件夹中。 注:导入需要的 cpu 架构的 so 库即可 打开app/build.gradle...
  • IOS 个推推送总结

    千次阅读 2016-01-30 15:26:25
    1.创建个推开发者帐号 创建个推开发者帐号,请访问个推开发者平台(dev.getui.com),点击注册进行开发者账号注册。 2.登记新应用 创建好账号进入个推开发者平台,首页展示的是如下界面,点击左上角“登记应用”...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,026,512
精华内容 410,604
关键字:

个推