# 野火IM 推送服务
作为野火IM的推送服务的演示，支持小米、华为、魅族、OPPO、Vivo、苹果apns和谷歌FCM。并且可以添加更多的推送厂商和自定义推送模式。

#### 工作原理
推送功能对于所有IM来说都是非常重要的功能，然而android系统又没有统一的推送服务，对接起来难度很大。另外一方面客户有不同对接需求，有的要求使用第三方，有的要求使用厂商推送，有的需要在海外添加谷歌推送，有的对推送的格式有不同的要求。

为了满足各种各样的需求，提供足够好的灵活性，野火IM把推送子系统独立出来，客户只要理解了推送子系统运行的原理，就能做好各种自定义处理。
![架构图](https://docs.wildfirechat.cn/architecture/wildfire_architecture.png)
> 如果架构图无法查看，可以点击[这里](https://docs.wildfirechat.cn/architecture/wildfire_architecture.png)查看

图中紫色部分为推送子系统，推送子系统的所有源码都是开源的，且可以随意修改。推送子系统的工作流程如下：
1. 应用启动后，推送SDK初始化，判断采用那种推送服务，比如华为手机就用华为推送，小米手机就用小米推送，或者全部或部分使用第三方推送。如果客户要加其它推送也是在这里加。选定好推送厂商后，就初始化对应推送厂商的SDK，注册成功后会得到推送token，调用IM SDK的setDeviceToken，传入推送token和类型。注意类型是可以扩展的，而且对IM系统没有任何影响的。
2. SDK被调用setDeviceToken后，会把推送token和类型传入到IM服务，IM服务为对应手机保存下来以备后用。事实上IM服务不需要理解token和type的含义，只需要透传给推送服务即可。
3. IM服务处理消息时发现用户不在线或者下发消息失败，则会启动是否要推送的决策，比如消息是否需要推送（预制消息已经支持，自定义消息需要传入push content），用户是否全局静音，会话是否被静音，客户有多少天没有登录（超过7天没登录就不推送）。达到推送条件后，跟把所有推送需要的内容打包发给推送服务。
4. 推送服务接收到IM服务的请求，把推送数据放到消费队列中并立即返回（IM服务不能被阻塞），然后逐步处理推送事件。每个推送事件中都包含了所有需要处理的数据，其中包括1步骤中的推送Token和类型，然后根据类型来调用对用推送厂商的服务，比如华为/小米/苹果/第三方厂商/谷歌/OPPO/Vivo等，调用他们的SDK进行推送。


#### 申请推送服务
客户需要自行去厂商申请推送服务并替换配置文件中的各项参数。我们提供的默认参数是服务工作的，需要替换。不排除推送厂商sdk接口有变化，需要自行调试，如果发现我们demo有问题，欢迎给我们提PR。

#### 编译
```
mvn package
```

#### 修改配置
本演示服务有1个工程配置文件和7个推送配置文件在工程的```config```目录下，请配置服务的端口和各个推送服务相关配置。如果有无法支持的推送类型，请修改客户端去掉不支持的类型（注意这里的配置文件要保留）。
请正确配置放到jar包所在的目录下的```config```目录下。

#### 证书
苹果和谷歌推送需要证书，请把对应证书分别放到apns和fcm目录下，然后修改配置文件中的证书路径。
同样把apns和fcm目录放到jar包所在目录

#### 运行
在```target```目录找到```push-XXXX.jar```，把jar包和放置配置文件的```config```目录放到一起，然后执行下面命令：
```
java -jar push-XXXXX.jar
```

#### 修改IM服务配置
修改IM服务的配置文件```wildfirechat.conf```，指向推送服务器的地址，修改完后需要重启
```
#*********************************************************************
# Push server configuration
#*********************************************************************
##安卓推送服务器地址
push.android.server.address http://localhost:8085/android/push
##苹果推送服务器地址
push.ios.server.address http://localhost:8085/ios/push
```

#### Android客户端的修改
Android客户端Push SDK是处理推送注册及接收的地方。这里是客户端进行推送对接的地方，有几点需要注意修改：
1. 选取您期望的推送，默认是加上了常见推送SDK，但实际上都会有各种原因只能选取部分，需要屏蔽掉您不需要的推送类型。
2. 如果支持FCM，需要判断是选取FCM还是国内推送厂商的问题。我们处理比较简单，如果你们能够更精准的判断，需要加上你们自己的判断。

#### 问题排查
如果遇到问题请按照以下步骤排查：
1. 确保程序是非启动状态，如果退回到桌面，应用还是激活的还会继续收消息，此时就不会走推送服务。应用在后台激活状态时应该走本地通知。
2. 确认客户端推送SDK是否正确的获取到token，是否调用了setDeviceToken，token和type是多少？
3. 确认消息是否是自定义消息，如果是自定义消息，push content是否带上有内容？自定义消息只有push content不为空才会推送。
4. 确认目标客户端是否7日之内登录过，超过7天是不推送的。
5. 确认目标客户是否设置了全局静音或会话静音。
6. 确认推送服务是否收到了推送信息，如果收到，token和type是否和步骤1一致，推送内容是否和2一致？
7. 如果推送内容正确到达推送服务，则后面的排查就跟IM服务完全无关了，是推送厂商推送服务的调试，需要客户自己按照推送厂商的官方文档进行调试。

#### 其它注意事项
Android推送服务有透传推送和通知栏推送两种推送方式，各个厂商的支持程度各异，一般情况下透传推送客户体验更好，但需要开通额外的权限比如自启动和后台等，需要用户进行设置；通知栏推送更简单，只弹出通知栏不拉起应用，但在音视频来电处理上赶不上透传，好处是不需要用户手动设置。我们提供的demo中使用的方式并不一定是最适合您的，还需要您根据实际情况来调整使用透传或通知栏。

#### 添加其它推送服务
由前面的介绍可以看出，推送子服务是独立于IM服务，而且客户端和服务器部分都是开源的，而且考虑到了扩展性，可以很容易地添加其它推送类型。具体步骤如下：
1. 必须理解推送的工作原理，知道流程是：客户端注册推送-》客户端注册推送成功得到deviceToken-》客户端调用设置deviceToken和类型，这两个数据被存储到IM服务。当IM服务需要推送时，IM服务打包推送信息（包括deviceToken和类型）请求到推送服务-》推送服务根据类型选择服务商推送数据。
2. 客户端扩展一个新的推送类型。
3. 客户端在应用启动时，添加处理这种推送类型的注册
4. 在注册成功后会得到deviceToken，调用IM SDK的setDeviceToken接口传人deviceToken和类型。
5. 推送服务添加对这种类型的处理。

#### 使用到的开源代码
1. [TypeBuilder](https://github.com/ikidou/TypeBuilder) 一个用于生成泛型的简易Builder

#### LICENSE
UNDER MIT LICENSE. 详情见LICENSE文件
