├── .github
└── ISSUE_TEMPLATE
│ └── bug-report.md
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── android
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── jeepeng
│ │ └── react
│ │ └── xgpush
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── jeepeng
│ │ │ └── react
│ │ │ └── xgpush
│ │ │ ├── Constants.java
│ │ │ ├── PushMessage.java
│ │ │ ├── PushModule.java
│ │ │ ├── PushPackage.java
│ │ │ └── receiver
│ │ │ ├── HWReceiver.java
│ │ │ └── MessageReceiver.java
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── jeepeng
│ └── react
│ └── xgpush
│ └── ExampleUnitTest.java
├── example
├── .babelrc
├── .buckconfig
├── .flowconfig
├── .gitattributes
├── .gitignore
├── .watchmanconfig
├── __tests__
│ └── index.js
├── android
│ ├── app
│ │ ├── BUCK
│ │ ├── build.gradle
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── assets
│ │ │ ├── index.android.bundle
│ │ │ └── index.android.bundle.meta
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── MainApplication.java
│ │ │ └── res
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── keystores
│ │ ├── BUCK
│ │ └── debug.keystore.properties
│ └── settings.gradle
├── app.json
├── app
│ ├── Touchable.js
│ └── index.js
├── index.js
├── ios
│ ├── example-tvOS
│ │ └── Info.plist
│ ├── example-tvOSTests
│ │ └── Info.plist
│ ├── example.xcodeproj
│ │ ├── project.pbxproj
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ ├── example-tvOS.xcscheme
│ │ │ └── example.xcscheme
│ ├── example
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.xib
│ │ ├── Images.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── Info.plist
│ │ ├── example.entitlements
│ │ └── main.m
│ └── exampleTests
│ │ ├── Info.plist
│ │ └── exampleTests.m
├── package-lock.json
└── package.json
├── index.js
├── ios
├── SDK
│ └── XGPush.h
├── XGPush.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcuserdata
│ │ │ └── Jeepeng.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata
│ │ └── Jeepeng.xcuserdatad
│ │ └── xcschemes
│ │ ├── XGPush.xcscheme
│ │ └── xcschememanagement.plist
├── XGPush
│ ├── XGPushManager.h
│ └── XGPushManager.m
└── libXG-SDK.a
├── package.json
└── react-native-xinge-push.podspec
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | **描述**
8 | 请清晰简洁地描述你遇到的问题
9 |
10 | **复现步骤**
11 | 重现bug的步骤:
12 | 1. Go to '...'
13 | 2. Click on '....'
14 | 3. Scroll down to '....'
15 | 4. See error
16 |
17 | **预期的行为**
18 | 请清晰简洁地描述你预期会发生什么
19 |
20 | **截图**
21 | 如果需要,请添加屏幕截图以帮助解释您的问题
22 |
23 | **手机 (请填写下面信息):**
24 | - 手机型号: [e.g. 华为 Mate 9]
25 | - 系统版本: [e.g. Android 8.0]
26 | - 版本 [e.g. 0.6]
27 |
28 | **附加信息**
29 | 在这里添加关于问题的其他信息
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 |
33 | # node.js
34 | #
35 | node_modules/
36 | npm-debug.log
37 | yarn-error.log
38 |
39 | # BUCK
40 | buck-out/
41 | \.buckd/
42 | *.keystore
43 |
44 | # fastlane
45 | #
46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47 | # screenshots whenever they are needed.
48 | # For more information about the recommended setup visit:
49 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
50 |
51 | fastlane/report.xml
52 | fastlane/Preview.html
53 | fastlane/screenshots
54 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | example/
2 |
3 | .idea
4 | android/build/
5 | android/*.iml
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 信鸽推送服务应该会在2020年10月31号之前停止免费服务,故 react-native-xinge-push 应该也不会再有维护。谢谢大家的支持~
2 |
3 |
4 | ## 版本对照表
5 | react-native-xinge-push | 信鸽SDK(Android) | 信鸽SDK(iOS)
6 | ---|---|---
7 | 1.1 | 4.3.5 | v3.3.7
8 | 1.0 | 4.3.2 | v3.3.5
9 | 0.6 | 3.2.2 | 3.1.1
10 | 0.4~0.5 | 3.2.2 | 2.5.0
11 | 0.3 | 3.1.0 | 2.5.0
12 |
13 | ## 简介 - 20191122 更新 Android SDK 4.3.5
14 | Android SDK 更新之后发现会有些异常无法启动service
15 | 需要配置:https://xg.qq.com/docs/android_access/android_p_compatibility.html
16 |
17 |
18 | ## 简介 - 20190809 正式更新
19 |
20 | 经过一段时间的项目测试和完善,虽然中间遇到很多推送的坑。但是还是一直坚持使用信鸽推送,第一免费,第二支持内地厂商通道以及海外FCM同时推送。
21 |
22 | ## TODO
23 | - [ ] 如何在React Native 中优雅的使用这个推送 (Redux+Saga实战)
24 |
25 | ## New Features
26 | - [x] Android 适配FCM,小米,华为(魅族没申请到无法测试)文档
27 | - [x] 支持厂商通道的intent来点击回调获取参数或者跳转自定义页面
28 | - [x] 修改注册机制,信鸽推送在一开启App时就开始注册而非在RN触发注册
29 | - [x] Android 配置无需在RN配置,直接在 app.gradle 文件配置即可
30 | - [x] Andrroid getInititalNotficaiton 功能完成并在FCM,小米,华为机均测试通过
31 | - [x] iOS 在getInititalNotficaiton 之后清除通知
32 |
33 | ## Done
34 | - [x] 支持Fcm 集成
35 | - [x] 计划更新 iOS SDK 到 v3.3.5
36 | - [x] 计划更新 Android SDK v4.3.2 厂商通道
37 | - [x] 升级信鸽Android SDK 到 v3.2.2
38 | - [x] 适配华为官方推送通道
39 | - [x] 适配小米官方推送通道
40 | - [x] 适配魅族官方推送通道
41 | - [x] 升级信鸽iOS SDK 到 v3.1.0
42 |
43 | ## 简介 - 20190227 更新
44 | 因为项目开发决定采用信鸽推送,鉴于信鸽官方并不支持 React Native,所幸有Jeepeng 推出了 https://github.com/Jeepeng/react-native-xinge-push, 是已经好久没有更新了。同时这个库遇到 https://github.com/Jeepeng/react-native-xinge-push/issues/22 这个问题,所幸https://github.com/wanxsb/react-native-xinge-push 在这个版本已经解决。接下去因为项目会涉及xinge推送的开发以及维护,所以会有些时间帮忙维护下一个库。本人比较熟悉iOS&Android原生开发,同时负责的团队也正在往React Native过渡,希望可以给社区贡献一点力量。
45 |
46 |
47 |
48 |
49 | ## install
50 | ```
51 | npm install --save https://github.com/PandaQQ/react-native-xinge-push.git
52 | ```
53 |
54 | ## link
55 |
56 | ```
57 | react-native link react-native-xinge-push
58 | ```
59 |
60 | ## usage
61 | ### Android
62 |
63 | Android 的推送简直就是个无敌大坑啊!!!!!但是终于我还是搞定啦哈哈哈哈~~
64 |
65 |
66 | #### Android 集成攻略
67 |
68 | 众所周知,当Application启动完成之后才开始启动React Native。所以在React Native中初始化并且注册信鸽推送服务其实并不是特别理想。因为当App 已经被杀死的时候,就无法获取推送的消息内容并作下一步的业务。所以在Android平台下,我们必须要注册信鸽服务于React Native之前。
69 |
70 |
71 | - 1. 在 build.gradle (Module:app) 下配置 manifestPlaceholders, (注意 my_xm_xg_id和my_xm_xg_key需要在XM-后添加id和key, 因为我发现Android读取全是数字的id和key会自动转成Float - *神一样的操作,写这个的人出来看我不打死他!*)
72 |
73 | ```javascript
74 | manifestPlaceholders = [
75 | XG_ACCESS_ID : "",
76 | XG_ACCESS_KEY: "",
77 | HW_APPID : "",
78 | PACKAGE_NAME : "",
79 | my_xm_xg_id : "XM-",
80 | my_xm_xg_key: "XM-",
81 | ]
82 | ```
83 |
84 | - 2. 在项目的AndroidManifest.xml
85 |
86 | ```xml
87 |
90 |
93 | ```
94 |
95 | - 3. 在项目的AndroidManifest.xml 中的 MainActivity下添加 intent-filter
96 |
97 | ```xml
98 |
105 |
106 |
107 |
108 |
109 |
112 |
113 |
114 | ```
115 |
116 | - 4. 在MainActivity 中添加 intent 接受方法
117 |
118 | ```java
119 | @Override
120 | public void onCreate(Bundle instance) {
121 |
122 | super.onCreate(instance);
123 | //// 集成厂商通道之后,点击推送通知使用 intent 推送内容
124 | Uri uri = getIntent().getData();
125 | PushMessage.getInstance().setAllValueIntentUrl(uri);
126 | }
127 | ```
128 |
129 | #### Android intent 测试
130 |
131 | https://xg.qq.com/docs/android_access/android_faq.html#消息点击事件以及跳转页面方法
132 |
133 | - 测试过上述连接给出的方法再做总结,下面这段代码不行,获取不到参数,但是和使用无关:
134 |
135 | ```java
136 |
137 | Uri uri = getIntent().getData();
138 | if (uri != null) {
139 | String url = uri.toString();
140 | UrlQuerySanitizer sanitizer = new UrlQuerySanitizer();
141 | sanitizer.setUnregisteredParameterValueSanitizer(UrlQuerySanitizer.getAllButNulLegal());
142 | sanitizer.parseUrl(url);
143 | String value1 = sanitizer.getValue("key1");
144 | String value2 = sanitizer.getValue("key2");
145 | Log.i("XG" , "value1 = " + value1 + " value2 = " + value2);
146 | }
147 |
148 | ```
149 |
150 | - intent 调用sample,注意key要符合定义,否则库收不到参数。(title, content和custom_content)
151 |
152 | ```
153 | xgscheme://com.xg.push/notify_detail?title=aa&content=bb&custom_content=
154 | ```
155 |
156 | #### FCM通道集成指南
157 | https://xg.qq.com/docs/android_access/FCM.html
158 |
159 | #### 小米通道集成指南
160 | https://xg.qq.com/docs/android_access/mi_push.html
161 |
162 | #### 华为推送通道集成指南
163 | http://xg.qq.com/docs/android_access/huawei_push.html
164 |
165 | 1. 确认已在信鸽管理台中「应用配置-厂商&海外通道」中填写相关的应用信息。通常,相关配置将在1个小时后生效,请您耐心等待,在生效后再进行下一个步骤
166 | 2. 将集成好的App(测试版本)安装在测试机上,并且运行App
167 | 3. 保持App在前台运行,尝试对设备进行单推/全推
168 | 4. 如果应用收到消息,将App退到后台,并且杀掉所有App进程
169 | 5. 再次进行单推/全推,如果能够收到推送,则表明厂商通道集成成功
170 |
171 | ###### 注意事项
172 | 消息目前将其理解为两类:静默消息和普通通知
173 | 静默消息不会弹窗,通知会弹窗
174 |
175 | 如果在EMUI 8.0(Android 8)上,出现发通知成功但通知栏不显示的情况,并在Logcat看到以下错误:
176 | ```
177 | E/NotificationService: No Channel found for pkg=com.jeepeng.push, channelId=null, id=995033369, tag=null, opPkg=com.huawei.android.pushagent, callingUid=10060, userId=0, incomingUserId=0, notificationUid=10261, notification=Notification(channel=null pri=0 contentView=null vibrate=null sound=default tick defaults=0x1 flags=0x10 color=0x00000000 vis=PRIVATE)
178 | ```
179 |
180 | 需要将`targetSdkVersion`[降到25](https://stackoverflow.com/questions/45668079/notificationchannel-issue-in-android-o)
181 |
182 | ####
183 |
184 |
185 |
186 | ### iOS
187 | AppDelegate.m:
188 |
189 | ```oc
190 | /**
191 | * Copyright (c) 2015-present, Facebook, Inc.
192 | * All rights reserved.
193 | *
194 | * This source code is licensed under the BSD-style license found in the
195 | * LICENSE file in the root directory of this source tree. An additional grant
196 | * of patent rights can be found in the PATENTS file in the same directory.
197 | */
198 |
199 | #import "AppDelegate.h"
200 |
201 | #import
202 | #import
203 | #import
204 | #import
205 |
206 | @implementation AppDelegate
207 |
208 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
209 | {
210 | NSURL *jsCodeLocation;
211 |
212 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
213 |
214 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
215 | moduleName:@"example"
216 | initialProperties:nil
217 | launchOptions:launchOptions];
218 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
219 |
220 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
221 | UIViewController *rootViewController = [UIViewController new];
222 | rootViewController.view = rootView;
223 | self.window.rootViewController = rootViewController;
224 | [self.window makeKeyAndVisible];
225 | // 统计消息推送的抵达情况
226 | [[XGPush defaultManager] reportXGNotificationInfo:launchOptions];
227 | return YES;
228 | }
229 |
230 | // Required to register for notifications
231 | - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
232 | {
233 | [XGPushManager didRegisterUserNotificationSettings:notificationSettings];
234 | }
235 |
236 | - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
237 | [XGPushManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
238 | }
239 |
240 | // Required for the registrationError event.
241 | - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
242 | NSLog(@"[XGPush] register APNS fail.\n[XGPush] reason : %@", error);
243 | [XGPushManager didFailToRegisterForRemoteNotificationsWithError:error];
244 | }
245 |
246 | // Required for the localNotification event.
247 | - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
248 | {
249 | [XGPushManager didReceiveLocalNotification:notification];
250 | }
251 |
252 | /**
253 | 收到通知消息的回调,通常此消息意味着有新数据可以读取(iOS 7.0+)
254 |
255 | @param application UIApplication 实例
256 | @param userInfo 推送时指定的参数
257 | @param completionHandler 完成回调
258 | */
259 | - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
260 | NSLog(@"[XGPush] receive slient Notification");
261 | NSLog(@"[XGPush] userinfo %@", userInfo);
262 | UIApplicationState state = [application applicationState];
263 | BOOL isClicked = (state != UIApplicationStateActive);
264 | NSMutableDictionary *remoteNotification = [NSMutableDictionary dictionaryWithDictionary:userInfo];
265 | if(isClicked) {
266 | remoteNotification[@"clicked"] = @YES;
267 | remoteNotification[@"background"] = @YES;
268 | }
269 | [[XGPush defaultManager] reportXGNotificationInfo:remoteNotification];
270 | [XGPushManager didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
271 | }
272 |
273 | @end
274 |
275 | ```
276 |
277 | ## Example
278 |
279 | see `example` folder for more details
280 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 26
5 | buildToolsVersion '27.0.3'
6 |
7 | defaultConfig {
8 | minSdkVersion 16
9 | targetSdkVersion 26
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | defaultConfig {
14 | consumerProguardFiles 'proguard-rules.pro'
15 | manifestPlaceholders = [
16 | XG_ACCESS_ID: "",
17 | XG_ACCESS_KEY: "",
18 | HW_APPID: ""
19 | ]
20 | }
21 |
22 | sourceSets {
23 | main {
24 | jniLibs.srcDirs = ['libs']
25 | }
26 | }
27 | }
28 |
29 | dependencies {
30 | compile fileTree(dir: 'libs', include: ['*.jar'])
31 | testCompile 'junit:junit:4.12'
32 | compile "com.facebook.react:react-native:+"
33 | compile "me.leolin:ShortcutBadger:1.1.21@aar"
34 | // compile 'com.tencent.xinge:xinge:3.2.4-beta'
35 | // compile 'com.tencent.wup:wup:1.0.0.E-release'
36 | // compile 'com.tencent.mid:mid:4.0.6-release'
37 | // compile 'com.tencent.xinge:xghw:3.2.4-beta'
38 | // compile 'com.tencent.xinge:mipush:3.2.4-beta'
39 | // compile 'com.tencent.xinge:xgmz:3.2.4-beta'
40 | //增加以下依赖
41 |
42 | implementation 'com.tencent.xinge:xinge:4.3.7-release'
43 | implementation 'com.tencent.wup:wup:1.0.0.E-Release'
44 | implementation 'com.tencent.jg:jg:1.1'
45 | implementation 'com.tencent.mid:mid:4.0.7-Release'
46 | implementation 'com.tencent.xinge:mipush:4.3.2-xiaomi-release'
47 | implementation 'com.tencent.xinge:xgmz:4.3.2-meizu-release'
48 | implementation 'com.tencent.xinge:xghw:4.3.2-huawei-release'
49 | //fcm通道需要增加以下依赖并将google-services.json放进你应用model的根路径下。
50 | implementation 'com.tencent.xinge:fcm:4.3.2-release'
51 | implementation 'com.google.firebase:firebase-messaging:17.3.1'
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/android/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Library/Android/SDK/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | ## 信鸽
20 | -keep public class * extends android.app.Service
21 | -keep public class * extends android.content.BroadcastReceiver
22 | -keep class com.tencent.android.tpush.** {*;}
23 | -keep class com.tencent.mid.** {*;}
24 | -keep class com.qq.taf.jce.** {*;}
25 | -keep class com.tencent.bigdata.** {*;}
26 |
27 | ## 华为通道
28 | -ignorewarning
29 | -keepattributes *Annotation*
30 | -keepattributes Exceptions
31 | -keepattributes InnerClasses
32 | -keepattributes Signature
33 | -keepattributes SourceFile,LineNumberTable
34 | -keep class com.hianalytics.android.**{*;}
35 | -keep class com.huawei.updatesdk.**{*;}
36 | -keep class com.huawei.hms.**{*;}
37 | -keep class com.huawei.android.hms.agent.**{*;}
38 |
39 | ## 小米通道
40 | -keep class com.xiaomi.**{*;}
41 | -keep public class * extends com.xiaomi.mipush.sdk.PushMessageReceiver
42 |
43 | ## 魅族通道
44 | -dontwarn com.meizu.cloud.pushsdk.**
45 | -keep class com.meizu.cloud.pushsdk.**{*;}
46 |
--------------------------------------------------------------------------------
/android/src/androidTest/java/com/jeepeng/react/xgpush/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.jeepeng.react.xgpush;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
8 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/android/src/main/java/com/jeepeng/react/xgpush/Constants.java:
--------------------------------------------------------------------------------
1 | package com.jeepeng.react.xgpush;
2 |
3 | /**
4 | * 常量
5 | * Created by Jeepeng on 16/8/15.
6 | */
7 | public class Constants {
8 | public static final String ACTION_ON_REGISTERED = "XGPushNotificationOnRegisterResult";
9 | public static final String ACTION_ON_TEXT_MESSAGE = "XGPushNotificationOnTextMessage";
10 | public static final String ACTION_ON_NOTIFICATION_SHOWED = "XGPushNotificationOnShowed";
11 | public static final String ACTION_ON_NOTIFICATION_CLICKED = "XGPushNotificationOnClicked";
12 |
13 | public static final String EVENT_REGISTERED = "remoteNotificationsRegistered";
14 | public static final String EVENT_REMOTE_NOTIFICATION_RECEIVED = "remoteNotificationReceived";
15 | public static final String EVENT_LOCAL_NOTIFICATION_RECEIVED = "localNotificationReceived";
16 | public static final String EVENT_MESSAGE_RECEIVED = "messageReceived";
17 | }
18 |
--------------------------------------------------------------------------------
/android/src/main/java/com/jeepeng/react/xgpush/PushMessage.java:
--------------------------------------------------------------------------------
1 | package com.jeepeng.react.xgpush;
2 |
3 | import android.net.Uri;
4 | import android.net.UrlQuerySanitizer;
5 | import android.util.Log;
6 |
7 | public class PushMessage {
8 | private static final PushMessage ourInstance = new PushMessage();
9 |
10 | public static PushMessage getInstance() {
11 | return ourInstance;
12 | }
13 |
14 | private String Title = null;
15 | private String Content = null;
16 | private String CustomContent = null;
17 | public boolean hasValue = false;
18 |
19 | public String getTitle() {
20 | return Title;
21 | }
22 |
23 | public void setTitle(String title) {
24 | Title = title;
25 | }
26 |
27 | public String getContent() {
28 | return Content;
29 | }
30 |
31 | public void setContent(String content) {
32 | Content = content;
33 | }
34 |
35 | public String getCustomContent() {
36 | return CustomContent;
37 | }
38 |
39 | public void setCustomContent(String customContent) {
40 | CustomContent = customContent;
41 | }
42 |
43 | public void clearAll() {
44 | CustomContent = null;
45 | Content = null;
46 | Title = null;
47 | hasValue = false;
48 | }
49 |
50 | public void setAllValue (String title, String content, String customContent) {
51 | this.Title = title;
52 | this.Content = content;
53 | this.CustomContent = customContent;
54 | this.hasValue = true;
55 | }
56 |
57 |
58 |
59 | private PushMessage() {
60 | }
61 |
62 | public void setAllValueIntentUrl (Uri pushUri) {
63 |
64 | if(pushUri != null) {
65 |
66 | String title= pushUri.getQueryParameter("title");
67 | String content= pushUri.getQueryParameter("content");
68 | String customContent = pushUri.getQueryParameter("custom_content");
69 |
70 | Log.d("XGQQ_PushMessage", "1. " + title);
71 | Log.d("XGQQ_PushMessage", "2. " + content);
72 | Log.d("XGQQ_PushMessage", "3. " + customContent);
73 |
74 | setAllValue(title, content, customContent);
75 | }
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/android/src/main/java/com/jeepeng/react/xgpush/PushModule.java:
--------------------------------------------------------------------------------
1 | package com.jeepeng.react.xgpush;
2 |
3 | import android.app.Activity;
4 | import android.content.BroadcastReceiver;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.IntentFilter;
8 | import android.support.annotation.Nullable;
9 | import android.util.Log;
10 |
11 | import android.content.pm.ApplicationInfo;
12 | import android.content.pm.PackageManager;
13 |
14 | import com.facebook.react.bridge.ActivityEventListener;
15 | import com.facebook.react.bridge.Arguments;
16 | import com.facebook.react.bridge.Callback;
17 | import com.facebook.react.bridge.LifecycleEventListener;
18 | import com.facebook.react.bridge.Promise;
19 | import com.facebook.react.bridge.ReactApplicationContext;
20 | import com.facebook.react.bridge.ReactContextBaseJavaModule;
21 | import com.facebook.react.bridge.ReactMethod;
22 | import com.facebook.react.bridge.WritableMap;
23 | import com.facebook.react.modules.core.DeviceEventManagerModule;
24 | import com.tencent.android.tpush.XGIOperateCallback;
25 | import com.tencent.android.tpush.XGLocalMessage;
26 | import com.tencent.android.tpush.XGPushClickedResult;
27 | import com.tencent.android.tpush.XGPushConfig;
28 | import com.tencent.android.tpush.XGPushManager;
29 | import com.tencent.android.tpush.encrypt.Rijndael;
30 |
31 | import me.leolin.shortcutbadger.ShortcutBadger;
32 |
33 | /**
34 | * 信鸽推送
35 | * Created by Jeepeng on 16/8/3.
36 | */
37 | public class PushModule extends ReactContextBaseJavaModule implements ActivityEventListener, LifecycleEventListener {
38 |
39 | public static final String MODULE_NAME = "XGPushManager";
40 |
41 | private Context reactContext;
42 | private int badge = 0;
43 | private String XM_ACCESS_ID = null;
44 | private String XM_ACCESS_KEY = null;
45 |
46 | public PushModule(ReactApplicationContext reactContext) {
47 | super(reactContext);
48 | reactContext.addActivityEventListener(this);
49 | reactContext.addLifecycleEventListener(this);
50 | this.reactContext = reactContext;
51 | registerReceivers();
52 |
53 | XGPushConfig.enableFcmPush(this.reactContext, true);
54 | XGPushConfig.setHuaweiDebug(true);
55 | XGPushConfig.enableOtherPush(this.reactContext, true);
56 |
57 | // Handle MI PUSH CONFIG
58 | ////////////////////////////////////////////////////
59 | ////////////////////////////////////////////////////
60 | try {
61 | ApplicationInfo appInfo = reactContext.getPackageManager().getApplicationInfo(reactContext.getPackageName(),
62 | PackageManager.GET_META_DATA);
63 |
64 | XM_ACCESS_ID = appInfo.metaData.getString("MY_XM_XG_ID");
65 | XM_ACCESS_KEY = appInfo.metaData.getString("MY_XM_XG_KEY");
66 |
67 | } catch (PackageManager.NameNotFoundException e) {
68 | e.printStackTrace();
69 | }
70 |
71 | if((XM_ACCESS_ID != null && XM_ACCESS_ID.length() != 0) || (XM_ACCESS_KEY != null && XM_ACCESS_KEY.length() != 0)) {
72 |
73 | Log.d("XGQQ", "1. " + XM_ACCESS_ID.replace("XM-", ""));
74 | Log.d("XGQQ", "2. " + XM_ACCESS_KEY.replace("XM-",""));
75 | XGPushConfig.setMiPushAppId(this.reactContext, XM_ACCESS_ID.replace("XM-", ""));
76 | XGPushConfig.setMiPushAppKey(this.reactContext, XM_ACCESS_KEY.replace("XM-",""));
77 | }
78 | ////////////////////////////////////////////////////
79 | ////////////////////////////////////////////////////
80 |
81 | XGPushManager.registerPush(this.reactContext);
82 |
83 | }
84 |
85 | @Override
86 | public String getName() {
87 | return MODULE_NAME;
88 | }
89 |
90 | private void sendEvent(String eventName, @Nullable WritableMap params) {
91 | if(getReactApplicationContext().hasActiveCatalystInstance()){
92 | getReactApplicationContext()
93 | .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
94 | .emit(eventName, params);
95 | }
96 | }
97 |
98 | private void registerReceivers() {
99 | IntentFilter intentFilter = new IntentFilter();
100 | intentFilter.addAction(Constants.ACTION_ON_REGISTERED);
101 | intentFilter.addAction(Constants.ACTION_ON_TEXT_MESSAGE);
102 | intentFilter.addAction(Constants.ACTION_ON_NOTIFICATION_CLICKED);
103 | intentFilter.addAction(Constants.ACTION_ON_NOTIFICATION_SHOWED);
104 |
105 | reactContext.registerReceiver(new BroadcastReceiver() {
106 | @Override
107 | public void onReceive(Context context, Intent intent) {
108 | WritableMap params = Arguments.createMap();
109 | switch (intent.getAction()){
110 | case Constants.ACTION_ON_REGISTERED:
111 | intent.getBundleExtra("notification");
112 | String token = intent.getStringExtra("token");
113 | params.putString("deviceToken", token);
114 |
115 | sendEvent(Constants.EVENT_REGISTERED, params);
116 | break;
117 | case Constants.ACTION_ON_TEXT_MESSAGE:
118 | String title = intent.getStringExtra("title");
119 | String content = intent.getStringExtra("content");
120 | String customContent = intent.getStringExtra("custom_content");
121 | params.putString("title", title);
122 | params.putString("content", content);
123 | params.putString("custom_content", customContent);
124 |
125 | sendEvent(Constants.EVENT_MESSAGE_RECEIVED, params);
126 | break;
127 | case Constants.ACTION_ON_NOTIFICATION_SHOWED:
128 | params.putString("title", intent.getStringExtra("title"));
129 | params.putString("content", intent.getStringExtra("content"));
130 | params.putString("custom_content", intent.getStringExtra("custom_content"));
131 |
132 | sendEvent(Constants.EVENT_REMOTE_NOTIFICATION_RECEIVED, params);
133 | break;
134 | case Constants.ACTION_ON_NOTIFICATION_CLICKED:
135 | params.putString("title", intent.getStringExtra("title"));
136 | params.putString("content", intent.getStringExtra("content"));
137 | params.putString("custom_content", intent.getStringExtra("custom_content"));
138 | params.putBoolean("clicked", true);
139 |
140 | sendEvent(Constants.EVENT_REMOTE_NOTIFICATION_RECEIVED, params);
141 | break;
142 | default:
143 | break;
144 | }
145 |
146 |
147 | }
148 | }, intentFilter);
149 | }
150 |
151 | /*****************************************************************
152 | * XGPushManager功能类
153 | * (对于本类提供的set和enable方法,要在XGPushManager接口前调用才能及时生效)
154 | *****************************************************************/
155 |
156 | /**
157 | * 启动并注册APP
158 | */
159 | @ReactMethod
160 | public void registerPush(final Promise promise) {
161 | XGPushManager.registerPush(this.reactContext, new XGIOperateCallback() {
162 | @Override
163 | public void onSuccess(Object date, int flag) {
164 | promise.resolve(date);
165 | }
166 |
167 | @Override
168 | public void onFail(Object data, int errCode, String msg) {
169 | promise.resolve(data);
170 | }
171 | });
172 | }
173 |
174 | /**
175 | * 启动并注册APP,同时绑定账号,推荐有帐号体系的APP使用
176 | * (此接口会覆盖设备之前绑定过的账号,仅当前注册的账号生效)
177 | * @param account
178 | * @param promise
179 | */
180 | @ReactMethod
181 | public void bindAccount(String account, final Promise promise) {
182 | XGPushManager.bindAccount(this.reactContext, account, new XGIOperateCallback() {
183 | @Override
184 | public void onSuccess(Object date, int flag) {
185 | promise.resolve(date);
186 | }
187 |
188 | @Override
189 | public void onFail(Object data, int errCode, String msg) {
190 | promise.reject(String.valueOf(errCode), msg);
191 | }
192 | });
193 | }
194 |
195 | /**
196 | * 启动并注册APP,同时绑定账号,推荐有帐号体系的APP使用
197 | * (此接口保留之前的账号,只做增加操作,一个token下最多只能有3个账号超过限制会自动顶掉之前绑定的账号)
198 | * @param account
199 | * @param promise
200 | */
201 | @ReactMethod
202 | public void appendAccount(String account, final Promise promise) {
203 | XGPushManager.appendAccount(this.reactContext, account, new XGIOperateCallback() {
204 | @Override
205 | public void onSuccess(Object date, int flag) {
206 | promise.resolve(date);
207 | }
208 |
209 | @Override
210 | public void onFail(Object data, int errCode, String msg) {
211 | promise.reject(String.valueOf(errCode), msg);
212 | }
213 | });
214 | }
215 |
216 | /**
217 | * 解绑指定账号
218 | * @param account
219 | * @param promise
220 | */
221 | @ReactMethod
222 | public void delAccount(String account, final Promise promise) {
223 | XGPushManager.delAccount(this.reactContext, account, new XGIOperateCallback() {
224 | @Override
225 | public void onSuccess(Object date, int flag) {
226 | promise.resolve(date);
227 | }
228 |
229 | @Override
230 | public void onFail(Object data, int errCode, String msg) {
231 | promise.reject(String.valueOf(errCode), msg);
232 | }
233 | });
234 | }
235 |
236 | /**
237 | * 反注册
238 | * @param promise
239 | */
240 | @ReactMethod
241 | public void unregisterPush(final Promise promise) {
242 | XGPushManager.unregisterPush(this.reactContext, new XGIOperateCallback() {
243 | @Override
244 | public void onSuccess(Object data, int flag) {
245 | WritableMap map = Arguments.createMap();
246 | map.putString("data", (String) data);
247 | map.putInt("flag", flag);
248 | promise.resolve(map);
249 | }
250 |
251 | @Override
252 | public void onFail(Object data, int errCode, String msg) {
253 | promise.reject(String.valueOf(errCode), msg);
254 | }
255 | });
256 | }
257 |
258 | /**
259 | * 设置tag
260 | * @param tagName
261 | */
262 | @ReactMethod
263 | public void setTag(String tagName) {
264 | XGPushManager.setTag(this.reactContext, tagName);
265 | }
266 |
267 | /**
268 | * 删除tag
269 | * @param tagName
270 | */
271 | @ReactMethod
272 | public void deleteTag(String tagName) {
273 | XGPushManager.deleteTag(this.reactContext, tagName);
274 | }
275 |
276 | @ReactMethod
277 | public void addLocalNotification(String title, String content) {
278 | XGLocalMessage message = new XGLocalMessage();
279 | message.setTitle(title);
280 | message.setContent(content);
281 | Log.i(MODULE_NAME, title);
282 | Log.i(MODULE_NAME, content);
283 | XGPushManager.addLocalNotification(this.reactContext, message);
284 | }
285 |
286 | /**
287 | * 检测通知栏是否关闭
288 | * @param promise
289 | */
290 | @ReactMethod
291 | public void isNotificationOpened(Promise promise) {
292 | promise.resolve(XGPushManager.isNotificationOpened(this.reactContext));
293 | }
294 |
295 | /*****************************************************************
296 | * XGPushConfig配置类
297 | * (对于本类提供的set和enable方法,要在XGPushManager接口前调用才能及时生效)
298 | *****************************************************************/
299 |
300 | /**
301 | * 初始化
302 | * @param accessId
303 | * @param accessKey
304 | */
305 | @ReactMethod
306 | public void init(int accessId, String accessKey) {
307 | XGPushConfig.setAccessId(this.reactContext, accessId);
308 | XGPushConfig.setAccessKey(this.reactContext, accessKey);
309 | }
310 |
311 | /**
312 | * 是否开启debug模式,即输出logcat日志重要:为保证数据的安全性,发布前必须设置为false)
313 | */
314 | @ReactMethod
315 | public void enableDebug(boolean isDebug) {
316 | XGPushConfig.enableDebug(this.reactContext, isDebug);
317 | }
318 |
319 | /**
320 | * 开启logcat输出,方便debug,发布时请关闭
321 | */
322 | @ReactMethod
323 | public void isEnableDebug(Promise promise) {
324 | promise.resolve(XGPushConfig.isEnableDebug(this.reactContext));
325 | }
326 |
327 | /**
328 | * 获取设备的token,只有注册成功才能获取到正常的结果
329 | * @param promise
330 | */
331 | @ReactMethod
332 | public void getToken(Promise promise) {
333 | promise.resolve(XGPushConfig.getToken(this.reactContext));
334 | }
335 |
336 | /**
337 | * 设置上报通知栏是否关闭 默认打开
338 | * @param debugMode
339 | */
340 | @ReactMethod
341 | public void setReportNotificationStatusEnable(boolean debugMode) {
342 | XGPushConfig.setReportNotificationStatusEnable(this.reactContext, debugMode);
343 | }
344 |
345 | /**
346 | * 设置上报APP 列表,用于智能推送 默认打开
347 | * @param debugMode
348 | */
349 | @ReactMethod
350 | public void setReportApplistEnable(boolean debugMode) {
351 | XGPushConfig.setReportApplistEnable(this.reactContext, debugMode);
352 | }
353 |
354 | @ReactMethod
355 | public void setAccessId(String accessId) {
356 | try{
357 | XGPushConfig.setAccessId(this.reactContext, Long.parseLong(accessId));
358 | } catch (NumberFormatException exception) {
359 | exception.printStackTrace();
360 | }
361 | }
362 |
363 | @ReactMethod
364 | public long getAccessId() {
365 | return XGPushConfig.getAccessId(this.reactContext);
366 | }
367 |
368 | @ReactMethod
369 | public void setAccessKey(String accessKey) {
370 | XGPushConfig.setAccessKey(this.reactContext, accessKey);
371 | }
372 |
373 | /**
374 | * 获取accessKey
375 | * @return accessKey
376 | */
377 | @ReactMethod
378 | public String getAccessKey() {
379 | return XGPushConfig.getAccessKey(this.reactContext);
380 | }
381 |
382 | /**
383 | * 第三方推送开关
384 | * 需要在 registerPush 之前调用
385 | */
386 | @ReactMethod
387 | public void enableOtherPush(boolean isEnable) {
388 | XGPushConfig.enableOtherPush(this.reactContext, isEnable);
389 | }
390 |
391 | @ReactMethod
392 | public void setHuaweiDebug(boolean isDebug) {
393 | XGPushConfig.setHuaweiDebug(isDebug);
394 | }
395 |
396 | @ReactMethod
397 | public void initXiaomi(String appId, String appKey) {
398 | XGPushConfig.setMiPushAppId(this.reactContext, appId);
399 | XGPushConfig.setMiPushAppKey(this.reactContext, appKey);
400 | }
401 |
402 | @ReactMethod
403 | public void initMeizu(String appId, String appKey) {
404 | //设置魅族APPID和APPKEY
405 | XGPushConfig.setMzPushAppId(this.reactContext, appId);
406 | XGPushConfig.setMzPushAppKey(this.reactContext, appKey);
407 | }
408 |
409 |
410 | @ReactMethod
411 | public void initFcm(boolean isEnable){
412 | XGPushConfig.enableFcmPush(this.reactContext, isEnable);
413 | }
414 |
415 | @ReactMethod
416 | public void getInitialNotification(Promise promise) {
417 |
418 | WritableMap params = Arguments.createMap();
419 | Log.d("getInitialNotification", ">>>>>>>>>>>>>>>>>");
420 | try {
421 |
422 | PushMessage mymessage = PushMessage.getInstance();
423 | if(mymessage.hasValue) {
424 | params.putString("title", mymessage.getTitle());
425 | params.putString("content", mymessage.getContent());
426 | params.putString("custom_content", mymessage.getCustomContent());
427 | Log.d("getInitialNotification", "title: "+ mymessage.getTitle()+ "content: " + mymessage.getContent() + "custom_content: " + mymessage.getCustomContent());
428 | mymessage.clearAll();
429 | promise.resolve(params);
430 | }
431 | else {
432 | promise.resolve(null);
433 | }
434 |
435 | } catch (Exception e) {
436 | Log.d("getInitialNotification", "Have Exception");
437 | e.printStackTrace();
438 | promise.resolve(null);
439 | }
440 |
441 | }
442 |
443 | @ReactMethod
444 | public void getApplicationIconBadgeNumber(Callback callback) {
445 | callback.invoke(this.badge);
446 | }
447 |
448 | @ReactMethod
449 | public void setApplicationIconBadgeNumber(int number) {
450 | this.badge = number;
451 | ShortcutBadger.applyCount(this.reactContext, number);
452 | }
453 |
454 | @Override
455 | public void onHostResume() {
456 | XGPushManager.onActivityStarted(getCurrentActivity());
457 | }
458 |
459 | @Override
460 | public void onHostPause() {
461 | XGPushManager.onActivityStoped(getCurrentActivity());
462 | }
463 |
464 | @Override
465 | public void onHostDestroy() {
466 |
467 | }
468 |
469 | @Override
470 | public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
471 |
472 | }
473 |
474 | @Override
475 | public void onNewIntent(Intent intent) {
476 | Log.d("onNewIntent", ">>>>>>>>>>>>>>>>>");
477 | Activity activity = getCurrentActivity();
478 | if (activity != null) {
479 | activity.setIntent(intent); // 后台运行时点击通知会调用
480 | }
481 | }
482 | }
483 |
--------------------------------------------------------------------------------
/android/src/main/java/com/jeepeng/react/xgpush/PushPackage.java:
--------------------------------------------------------------------------------
1 | package com.jeepeng.react.xgpush;
2 |
3 | import com.facebook.react.ReactPackage;
4 | import com.facebook.react.bridge.JavaScriptModule;
5 | import com.facebook.react.bridge.NativeModule;
6 | import com.facebook.react.bridge.ReactApplicationContext;
7 | import com.facebook.react.uimanager.ViewManager;
8 |
9 | import java.util.ArrayList;
10 | import java.util.Collections;
11 | import java.util.List;
12 |
13 | /**
14 | * 信鸽推送
15 | * Created by Jeepeng on 16/8/3.
16 | */
17 | public class PushPackage implements ReactPackage {
18 | @Override
19 | public List createNativeModules(ReactApplicationContext reactContext) {
20 | List modules = new ArrayList<>();
21 | modules.add(new PushModule(reactContext));
22 | return modules;
23 | }
24 |
25 | @Override
26 | public List createViewManagers(ReactApplicationContext reactContext) {
27 | return Collections.emptyList();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/android/src/main/java/com/jeepeng/react/xgpush/receiver/HWReceiver.java:
--------------------------------------------------------------------------------
1 | package com.jeepeng.react.xgpush.receiver;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.os.Environment;
6 | import android.os.Looper;
7 | import android.widget.Toast;
8 |
9 | import com.huawei.hms.support.api.push.PushReceiver;
10 |
11 | import java.io.FileWriter;
12 | import java.io.IOException;
13 |
14 | public class HWReceiver extends PushReceiver {
15 |
16 | @Override
17 | public void onEvent(Context context, Event arg1, Bundle arg2) {
18 | super.onEvent(context, arg1, arg2);
19 |
20 | showToast("onEvent" + arg1 + " Bundle " + arg2 , context);
21 | }
22 |
23 | @Override
24 | public boolean onPushMsg(Context context, byte[] arg1, Bundle arg2) {
25 |
26 | showToast("onPushMsg" + new String(arg1) + " Bundle " + arg2 , context);
27 | return super.onPushMsg(context, arg1, arg2);
28 | }
29 |
30 | @Override
31 | public void onPushMsg(Context context, byte[] arg1, String arg2) {
32 |
33 | showToast("onPushMsg" + new String(arg1) + " arg2 " + arg2 , context);
34 | super.onPushMsg(context, arg1, arg2);
35 | }
36 |
37 | @Override
38 | public void onPushState(Context context, boolean arg1) {
39 |
40 | showToast("onPushState" + arg1, context);
41 | super.onPushState(context, arg1);
42 | }
43 |
44 | @Override
45 | public void onToken(Context context, String arg1, Bundle arg2) {
46 | super.onToken(context, arg1, arg2);
47 |
48 | showToast(" onToken" + arg1 + "bundke " + arg2, context);
49 | }
50 |
51 | @Override
52 | public void onToken(Context context, String arg1) {
53 | super.onToken(context, arg1);
54 | showToast(" onToken" + arg1 , context);
55 | }
56 |
57 | public void showToast(final String toast, final Context context)
58 | {
59 |
60 | new Thread(new Runnable() {
61 |
62 | @Override
63 | public void run() {
64 | Looper.prepare();
65 | Toast.makeText(context, toast, Toast.LENGTH_SHORT).show();
66 | Looper.loop();
67 | }
68 | }).start();
69 | }
70 |
71 | private void writeToFile(String conrent) {
72 | String SDPATH = Environment.getExternalStorageDirectory() + "/huawei.txt";
73 | try {
74 | FileWriter fileWriter = new FileWriter(SDPATH, true);
75 |
76 | fileWriter.write(conrent+"\r\n");
77 | fileWriter.flush();
78 | fileWriter.close();
79 | } catch (IOException e) {
80 | // TODO Auto-generated catch block
81 | e.printStackTrace();
82 | }
83 | }
84 |
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/android/src/main/java/com/jeepeng/react/xgpush/receiver/MessageReceiver.java:
--------------------------------------------------------------------------------
1 | package com.jeepeng.react.xgpush.receiver;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 |
7 | import com.jeepeng.react.xgpush.PushMessage;
8 | import com.jeepeng.react.xgpush.Constants;
9 | import com.tencent.android.tpush.XGPushBaseReceiver;
10 | import com.tencent.android.tpush.XGPushClickedResult;
11 | import com.tencent.android.tpush.XGPushRegisterResult;
12 | import com.tencent.android.tpush.XGPushShowedResult;
13 | import com.tencent.android.tpush.XGPushTextMessage;
14 |
15 | import org.json.JSONException;
16 | import org.json.JSONObject;
17 |
18 | import me.leolin.shortcutbadger.ShortcutBadger;
19 |
20 | /**
21 | * 消息接收器
22 | * Created by Jeepeng on 16/8/4.
23 | */
24 | public class MessageReceiver extends XGPushBaseReceiver {
25 |
26 | /**
27 | * 注册结果
28 | * @param context
29 | * @param errorCode
30 | * @param xgPushRegisterResult
31 | */
32 | @Override
33 | public void onRegisterResult(Context context, int errorCode, XGPushRegisterResult xgPushRegisterResult) {
34 | if(errorCode == 0) {
35 | Intent intent = new Intent(Constants.ACTION_ON_REGISTERED);
36 | intent.putExtra("token", xgPushRegisterResult.getToken());
37 | context.sendBroadcast(intent);
38 | }
39 | }
40 |
41 | /**
42 | * 反注册结果
43 | * @param context
44 | * @param errorCode
45 | */
46 | @Override
47 | public void onUnregisterResult(Context context, int errorCode) {
48 |
49 | }
50 |
51 |
52 | /**
53 | * 设置标签结果
54 | * @param context
55 | * @param errorCode
56 | * @param tagName
57 | */
58 | @Override
59 | public void onSetTagResult(Context context, int errorCode, String tagName) {
60 |
61 | }
62 |
63 | /**
64 | * 删除标签结果
65 | * @param context
66 | * @param errorCode
67 | * @param tagName
68 | */
69 | @Override
70 | public void onDeleteTagResult(Context context, int errorCode, String tagName) {
71 |
72 | }
73 |
74 | /**
75 | * 收到消息
76 | * @param context
77 | * @param xgPushTextMessage
78 | */
79 | @Override
80 | public void onTextMessage(Context context, XGPushTextMessage xgPushTextMessage) {
81 | Intent intent = new Intent(Constants.ACTION_ON_TEXT_MESSAGE);
82 | intent.putExtra("title", xgPushTextMessage.getTitle());
83 | intent.putExtra("content", xgPushTextMessage.getContent());
84 | intent.putExtra("custom_content", xgPushTextMessage.getCustomContent());
85 | context.sendBroadcast(intent);
86 | }
87 |
88 | /**
89 | * 通知被打开触发的结果
90 | * @param context
91 | * @param notification
92 | */
93 | @Override
94 | public void onNotifactionClickedResult(Context context, XGPushClickedResult notification) {
95 | if (context == null || notification == null) {
96 | return;
97 | }
98 | if (notification.getActionType() == XGPushClickedResult.NOTIFACTION_CLICKED_TYPE) {
99 | // 通知在通知栏被点击啦。。。。。
100 |
101 | PushMessage message = PushMessage.getInstance();
102 | message.setAllValue(notification.getTitle(), notification.getContent(), notification.getCustomContent());
103 |
104 |
105 | Intent intent = new Intent(Constants.ACTION_ON_NOTIFICATION_CLICKED);
106 | Bundle bundle = new Bundle();
107 | bundle.putString("content", notification.getContent());
108 | bundle.putString("title", notification.getTitle());
109 | bundle.putString("custom_content", notification.getCustomContent());
110 | intent.putExtra("notification", bundle);
111 |
112 | intent.putExtra("title", notification.getTitle());
113 | intent.putExtra("content", notification.getContent());
114 | intent.putExtra("custom_content", notification.getCustomContent());
115 | intent.putExtra("activity", notification.getActivityName());
116 | intent.putExtra("msgId", notification.getMsgId());
117 | intent.putExtra("notificationActionType", notification.getNotificationActionType());
118 | context.sendBroadcast(intent);
119 | } else if (notification.getActionType() == XGPushClickedResult.NOTIFACTION_DELETED_TYPE) {
120 | // 通知被清除啦。。。。
121 | // APP自己处理通知被清除后的相关动作
122 | }
123 | }
124 |
125 | /**
126 | * 通知被展示触发的结果,可以在此保存APP收到的通知
127 | * @param context
128 | * @param xgPushShowedResult
129 | */
130 | @Override
131 | public void onNotifactionShowedResult(Context context, XGPushShowedResult xgPushShowedResult) {
132 | // set app icon badge
133 | try {
134 | JSONObject obj = new JSONObject(xgPushShowedResult.getCustomContent());
135 | int badge = obj.optInt("badge", -1);
136 | if (badge >= 0) {
137 | ShortcutBadger.applyCount(context, badge);
138 | }
139 | } catch (JSONException e) {
140 | e.printStackTrace();
141 | }
142 | Intent intent = new Intent(Constants.ACTION_ON_NOTIFICATION_SHOWED);
143 | Bundle bundle = new Bundle();
144 | bundle.putString("content", xgPushShowedResult.getContent());
145 | bundle.putString("title", xgPushShowedResult.getTitle());
146 | bundle.putString("custom_content", xgPushShowedResult.getCustomContent());
147 | intent.putExtra("notification", bundle);
148 |
149 | intent.putExtra("title", xgPushShowedResult.getTitle());
150 | intent.putExtra("content", xgPushShowedResult.getContent());
151 | intent.putExtra("custom_content", xgPushShowedResult.getCustomContent());
152 | intent.putExtra("activity", xgPushShowedResult.getActivity());
153 | intent.putExtra("msgId", xgPushShowedResult.getMsgId());
154 | intent.putExtra("notificationId", xgPushShowedResult.getNotifactionId());
155 | intent.putExtra("notificationActionType", xgPushShowedResult.getNotificationActionType());
156 | context.sendBroadcast(intent);
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/android/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | react-native-xinge-push
3 |
4 |
--------------------------------------------------------------------------------
/android/src/test/java/com/jeepeng/react/xgpush/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.jeepeng.react.xgpush;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/example/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react-native"]
3 | }
4 |
--------------------------------------------------------------------------------
/example/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/example/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | ; We fork some components by platform
3 | .*/*[.]android.js
4 |
5 | ; Ignore "BUCK" generated dirs
6 | /\.buckd/
7 |
8 | ; Ignore unexpected extra "@providesModule"
9 | .*/node_modules/.*/node_modules/fbjs/.*
10 |
11 | ; Ignore duplicate module providers
12 | ; For RN Apps installed via npm, "Libraries" folder is inside
13 | ; "node_modules/react-native" but in the source repo it is in the root
14 | .*/Libraries/react-native/React.js
15 |
16 | ; Ignore polyfills
17 | .*/Libraries/polyfills/.*
18 |
19 | ; Ignore metro
20 | .*/node_modules/metro/.*
21 |
22 | [include]
23 |
24 | [libs]
25 | node_modules/react-native/Libraries/react-native/react-native-interface.js
26 | node_modules/react-native/flow/
27 | node_modules/react-native/flow-github/
28 |
29 | [options]
30 | emoji=true
31 |
32 | module.system=haste
33 |
34 | munge_underscores=true
35 |
36 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
37 |
38 | module.file_ext=.js
39 | module.file_ext=.jsx
40 | module.file_ext=.json
41 | module.file_ext=.native.js
42 |
43 | suppress_type=$FlowIssue
44 | suppress_type=$FlowFixMe
45 | suppress_type=$FlowFixMeProps
46 | suppress_type=$FlowFixMeState
47 |
48 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
49 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
50 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
51 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
52 |
53 | unsafe.enable_getters_and_setters=true
54 |
55 | [version]
56 | ^0.61.0
57 |
--------------------------------------------------------------------------------
/example/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 |
33 | # node.js
34 | #
35 | node_modules/
36 | npm-debug.log
37 | yarn-error.log
38 |
39 | # BUCK
40 | buck-out/
41 | \.buckd/
42 | *.keystore
43 |
44 | # fastlane
45 | #
46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47 | # screenshots whenever they are needed.
48 | # For more information about the recommended setup visit:
49 | # https://docs.fastlane.tools/best-practices/source-control/
50 |
51 | */fastlane/report.xml
52 | */fastlane/Preview.html
53 | */fastlane/screenshots
54 |
55 | /android/app/release/
56 |
--------------------------------------------------------------------------------
/example/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/example/__tests__/index.js:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import React from 'react';
3 | import Index from '../index.js';
4 |
5 | // Note: test renderer must be required after react-native.
6 | import renderer from 'react-test-renderer';
7 |
8 | it('renders correctly', () => {
9 | const tree = renderer.create(
10 |
11 | );
12 | });
13 |
--------------------------------------------------------------------------------
/example/android/app/BUCK:
--------------------------------------------------------------------------------
1 | # To learn about Buck see [Docs](https://buckbuild.com/).
2 | # To run your application with Buck:
3 | # - install Buck
4 | # - `npm start` - to start the packager
5 | # - `cd android`
6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8 | # - `buck install -r android/app` - compile, install and run application
9 | #
10 |
11 | lib_deps = []
12 |
13 | for jarfile in glob(['libs/*.jar']):
14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')]
15 | lib_deps.append(':' + name)
16 | prebuilt_jar(
17 | name = name,
18 | binary_jar = jarfile,
19 | )
20 |
21 | for aarfile in glob(['libs/*.aar']):
22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')]
23 | lib_deps.append(':' + name)
24 | android_prebuilt_aar(
25 | name = name,
26 | aar = aarfile,
27 | )
28 |
29 | android_library(
30 | name = "all-libs",
31 | exported_deps = lib_deps,
32 | )
33 |
34 | android_library(
35 | name = "app-code",
36 | srcs = glob([
37 | "src/main/java/**/*.java",
38 | ]),
39 | deps = [
40 | ":all-libs",
41 | ":build_config",
42 | ":res",
43 | ],
44 | )
45 |
46 | android_build_config(
47 | name = "build_config",
48 | package = "com.example",
49 | )
50 |
51 | android_resource(
52 | name = "res",
53 | package = "com.example",
54 | res = "src/main/res",
55 | )
56 |
57 | android_binary(
58 | name = "app",
59 | keystore = "//android/keystores:debug",
60 | manifest = "src/main/AndroidManifest.xml",
61 | package_type = "debug",
62 | deps = [
63 | ":app-code",
64 | ],
65 | )
66 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 |
3 | import com.android.build.OutputFile
4 |
5 | /**
6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
7 | * and bundleReleaseJsAndAssets).
8 | * These basically call `react-native bundle` with the correct arguments during the Android build
9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
10 | * bundle directly from the development server. Below you can see all the possible configurations
11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the
12 | * `apply from: "../../node_modules/react-native/react.gradle"` line.
13 | *
14 | * project.ext.react = [
15 | * // the name of the generated asset file containing your JS bundle
16 | * bundleAssetName: "index.android.bundle",
17 | *
18 | * // the entry file for bundle generation
19 | * entryFile: "index.android.js",
20 | *
21 | * // whether to bundle JS and assets in debug mode
22 | * bundleInDebug: false,
23 | *
24 | * // whether to bundle JS and assets in release mode
25 | * bundleInRelease: true,
26 | *
27 | * // whether to bundle JS and assets in another build variant (if configured).
28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
29 | * // The configuration property can be in the following formats
30 | * // 'bundleIn${productFlavor}${buildType}'
31 | * // 'bundleIn${buildType}'
32 | * // bundleInFreeDebug: true,
33 | * // bundleInPaidRelease: true,
34 | * // bundleInBeta: true,
35 | *
36 | * // whether to disable dev mode in custom build variants (by default only disabled in release)
37 | * // for example: to disable dev mode in the staging build type (if configured)
38 | * devDisabledInStaging: true,
39 | * // The configuration property can be in the following formats
40 | * // 'devDisabledIn${productFlavor}${buildType}'
41 | * // 'devDisabledIn${buildType}'
42 | *
43 | * // the root of your project, i.e. where "package.json" lives
44 | * root: "../../",
45 | *
46 | * // where to put the JS bundle asset in debug mode
47 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
48 | *
49 | * // where to put the JS bundle asset in release mode
50 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
51 | *
52 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
53 | * // require('./image.png')), in debug mode
54 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
55 | *
56 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
57 | * // require('./image.png')), in release mode
58 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
59 | *
60 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
61 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
62 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle
63 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
64 | * // for example, you might want to remove it from here.
65 | * inputExcludes: ["android/**", "ios/**"],
66 | *
67 | * // override which node gets called and with what additional arguments
68 | * nodeExecutableAndArgs: ["node"],
69 | *
70 | * // supply additional arguments to the packager
71 | * extraPackagerArgs: []
72 | * ]
73 | */
74 |
75 | project.ext.react = [
76 | entryFile: "index.js"
77 | ]
78 |
79 | apply from: "../../node_modules/react-native/react.gradle"
80 |
81 | /**
82 | * Set this to true to create two separate APKs instead of one:
83 | * - An APK that only works on ARM devices
84 | * - An APK that only works on x86 devices
85 | * The advantage is the size of the APK is reduced by about 4MB.
86 | * Upload all the APKs to the Play Store and people will download
87 | * the correct one based on the CPU architecture of their device.
88 | */
89 | def enableSeparateBuildPerCPUArchitecture = false
90 |
91 | /**
92 | * Run Proguard to shrink the Java bytecode in release builds.
93 | */
94 | def enableProguardInReleaseBuilds = false
95 |
96 | android {
97 | compileSdkVersion 26
98 | buildToolsVersion '27.0.3'
99 |
100 | defaultConfig {
101 | applicationId "com.jeepeng.push"
102 | minSdkVersion 16
103 | targetSdkVersion 26
104 | versionCode 3
105 | versionName "1.0.1"
106 | ndk {
107 | abiFilters "armeabi-v7a", "x86"
108 | }
109 | manifestPlaceholders = [
110 | XG_ACCESS_ID: "2100209996",
111 | XG_ACCESS_KEY: "AHW931HVZ42A",
112 | HW_APPID: "100225811",
113 | PACKAGE_NAME: "com.jeepeng.push"
114 | ]
115 | }
116 | splits {
117 | abi {
118 | reset()
119 | enable enableSeparateBuildPerCPUArchitecture
120 | universalApk false // If true, also generate a universal APK
121 | include "armeabi-v7a", "x86"
122 | }
123 | }
124 | buildTypes {
125 | release {
126 | minifyEnabled enableProguardInReleaseBuilds
127 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
128 | }
129 | }
130 | // applicationVariants are e.g. debug, release
131 | applicationVariants.all { variant ->
132 | variant.outputs.each { output ->
133 | // For each separate APK per architecture, set a unique version code as described here:
134 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
135 | def versionCodes = ["armeabi-v7a":1, "x86":2]
136 | def abi = output.getFilter(OutputFile.ABI)
137 | if (abi != null) { // null for the universal-debug, universal-release variants
138 | output.versionCodeOverride =
139 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
140 | }
141 | }
142 | }
143 | }
144 |
145 | dependencies {
146 | compile project(':react-native-xinge-push')
147 | compile fileTree(dir: "libs", include: ["*.jar"])
148 | compile "com.android.support:appcompat-v7:26.1.0"
149 | compile "com.facebook.react:react-native:+" // From node_modules
150 | }
151 |
152 | // Run this once to be able to run the application with BUCK
153 | // puts all compile dependencies into folder libs for BUCK to use
154 | task copyDownloadableDepsToLibs(type: Copy) {
155 | from configurations.compile
156 | into 'libs'
157 | }
158 |
--------------------------------------------------------------------------------
/example/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Disabling obfuscation is useful if you collect stack traces from production crashes
20 | # (unless you are using a system that supports de-obfuscate the stack traces).
21 | -dontobfuscate
22 |
23 | # React Native
24 |
25 | # Keep our interfaces so they can be used by other ProGuard rules.
26 | # See http://sourceforge.net/p/proguard/bugs/466/
27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
30 |
31 | # Do not strip any method/class that is annotated with @DoNotStrip
32 | -keep @com.facebook.proguard.annotations.DoNotStrip class *
33 | -keep @com.facebook.common.internal.DoNotStrip class *
34 | -keepclassmembers class * {
35 | @com.facebook.proguard.annotations.DoNotStrip *;
36 | @com.facebook.common.internal.DoNotStrip *;
37 | }
38 |
39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
40 | void set*(***);
41 | *** get*();
42 | }
43 |
44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; }
46 | -keepclassmembers,includedescriptorclasses class * { native ; }
47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; }
48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; }
49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; }
50 |
51 | -dontwarn com.facebook.react.**
52 |
53 | # TextLayoutBuilder uses a non-public Android constructor within StaticLayout.
54 | # See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details.
55 | -dontwarn android.text.StaticLayout
56 |
57 | # okhttp
58 |
59 | -keepattributes Signature
60 | -keepattributes *Annotation*
61 | -keep class okhttp3.** { *; }
62 | -keep interface okhttp3.** { *; }
63 | -dontwarn okhttp3.**
64 |
65 | # okio
66 |
67 | -keep class sun.misc.Unsafe { *; }
68 | -dontwarn java.nio.file.*
69 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
70 | -dontwarn okio.**
71 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
15 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/example/android/app/src/main/assets/index.android.bundle.meta:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PandaQQ/react-native-xinge-push/3b77b89fa834236fde2220f600d388a4f2d35ec8/example/android/app/src/main/assets/index.android.bundle.meta
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/example/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import com.facebook.react.ReactActivity;
4 |
5 | public class MainActivity extends ReactActivity {
6 |
7 | /**
8 | * Returns the name of the main component registered from JavaScript.
9 | * This is used to schedule rendering of the component.
10 | */
11 | @Override
12 | protected String getMainComponentName() {
13 | return "example";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/example/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import android.app.Application;
4 |
5 | import com.facebook.react.ReactApplication;
6 | import com.jeepeng.react.xgpush.PushPackage;
7 | import com.facebook.react.ReactNativeHost;
8 | import com.facebook.react.ReactPackage;
9 | import com.facebook.react.shell.MainReactPackage;
10 | import com.facebook.soloader.SoLoader;
11 |
12 | import java.util.Arrays;
13 | import java.util.List;
14 |
15 | public class MainApplication extends Application implements ReactApplication {
16 |
17 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
18 | @Override
19 | public boolean getUseDeveloperSupport() {
20 | return BuildConfig.DEBUG;
21 | }
22 |
23 | @Override
24 | protected List getPackages() {
25 | return Arrays.asList(
26 | new MainReactPackage(),
27 | new PushPackage()
28 | );
29 | }
30 |
31 | @Override
32 | protected String getJSMainModuleName() {
33 | return "index";
34 | }
35 | };
36 |
37 | @Override
38 | public ReactNativeHost getReactNativeHost() {
39 | return mReactNativeHost;
40 | }
41 |
42 | @Override
43 | public void onCreate() {
44 | super.onCreate();
45 | SoLoader.init(this, /* native exopackage */ false);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PandaQQ/react-native-xinge-push/3b77b89fa834236fde2220f600d388a4f2d35ec8/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PandaQQ/react-native-xinge-push/3b77b89fa834236fde2220f600d388a4f2d35ec8/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PandaQQ/react-native-xinge-push/3b77b89fa834236fde2220f600d388a4f2d35ec8/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PandaQQ/react-native-xinge-push/3b77b89fa834236fde2220f600d388a4f2d35ec8/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RN-XGPush
3 |
4 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | google()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.1.0'
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | mavenLocal()
19 | jcenter()
20 | maven {
21 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
22 | url "$rootDir/../node_modules/react-native/android"
23 | }
24 | google()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | android.useDeprecatedNdk=true
21 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PandaQQ/react-native-xinge-push/3b77b89fa834236fde2220f600d388a4f2d35ec8/example/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Mar 27 17:51:16 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/example/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/example/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/example/android/keystores/BUCK:
--------------------------------------------------------------------------------
1 | keystore(
2 | name = "debug",
3 | properties = "debug.keystore.properties",
4 | store = "debug.keystore",
5 | visibility = [
6 | "PUBLIC",
7 | ],
8 | )
9 |
--------------------------------------------------------------------------------
/example/android/keystores/debug.keystore.properties:
--------------------------------------------------------------------------------
1 | key.store=debug.keystore
2 | key.alias=androiddebugkey
3 | key.store.password=android
4 | key.alias.password=android
5 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'example'
2 | include ':react-native-xinge-push'
3 | project(':react-native-xinge-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-xinge-push/android')
4 |
5 | include ':app'
6 |
--------------------------------------------------------------------------------
/example/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "displayName": "example"
4 | }
--------------------------------------------------------------------------------
/example/app/Touchable.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Jeepeng on 2017/3/3.
3 | */
4 |
5 | import React from 'react';
6 | import {
7 | Platform,
8 | TouchableNativeFeedback,
9 | TouchableHighlight,
10 | } from 'react-native';
11 |
12 | const Touchable = ({ onPress, children, style }) => {
13 | const child = React.Children.only(children);
14 | if (Platform.OS === 'android') {
15 | return (
16 |
17 | {child}
18 |
19 | );
20 | }
21 | return (
22 |
23 | {child}
24 |
25 | );
26 | };
27 |
28 | export default Touchable;
29 |
--------------------------------------------------------------------------------
/example/app/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Sample React Native App
3 | * https://github.com/facebook/react-native
4 | * @flow
5 | */
6 |
7 | import React, { Component } from 'react';
8 | import {
9 | Platform,
10 | StyleSheet,
11 | Text,
12 | View,
13 | TouchableNativeFeedback,
14 | TouchableHighlight
15 | } from 'react-native';
16 | import XGPush from 'react-native-xinge-push';
17 |
18 | const Touchable = Platform.OS === 'android' ? TouchableNativeFeedback : TouchableHighlight;
19 |
20 | class Example extends Component {
21 |
22 | constructor() {
23 | super();
24 | this.state = {
25 | isDebug: false
26 | };
27 | this._enableDebug = this._enableDebug.bind(this);
28 | this._isEnableDebug = this._isEnableDebug.bind(this);
29 |
30 | // 初始化推送
31 | this.initPush();
32 | }
33 |
34 | initPush() {
35 | XGPush.enableDebug(true)
36 | // 初始化
37 | if(Platform.OS === 'android') {
38 | // 请将1111111111修改为APP的AccessId,10位数字
39 | // 请将YOUR_ACCESS_KEY修改为APP的AccessKey
40 | XGPush.init(2100209996, 'AHW931HVZ42A');
41 | } else {
42 | // 请将1111111111修改为APP的AccessId,10位数字
43 | // 请将YOUR_ACCESS_KEY修改为APP的AccessKey
44 | XGPush.init(2200209997, 'ITD46N87JA4K');
45 | }
46 |
47 | XGPush.setHuaweiDebug(true);
48 |
49 | // 小米
50 | XGPush.initXiaomi('appId', 'appKey');
51 |
52 | // 魅族
53 | XGPush.initMeizu('appId', 'appKey');
54 |
55 | // 华为请到 build.gradle manifestPlaceholders 配置
56 |
57 | // 第三方推送开关(华为、小米、魅族)
58 | XGPush.enableOtherPush(true);
59 |
60 | // 注册
61 | XGPush.register('jeepeng')
62 | .then(result => {
63 | // do something
64 | })
65 | .catch(err => {
66 | console.log(err);
67 | });
68 | }
69 |
70 | componentDidMount() {
71 | XGPush.addEventListener('register', this._onRegister);
72 | XGPush.addEventListener('message', this._onMessage);
73 | XGPush.addEventListener('notification', this._onNotification);
74 | }
75 |
76 | componentWillUnmount() {
77 | XGPush.removeEventListener('register', this._onRegister);
78 | XGPush.removeEventListener('message', this._onMessage);
79 | XGPush.removeEventListener('notification', this._onNotification);
80 | }
81 |
82 | /**
83 | * 注册成功
84 | * @param deviceToken
85 | * @private
86 | */
87 | _onRegister(deviceToken) {
88 | alert('onRegister: ' + deviceToken);
89 | }
90 |
91 | /**
92 | * 透传消息到达
93 | * @param message
94 | * @private
95 | */
96 | _onMessage(message) {
97 | alert('收到透传消息: ' + JSON.stringify(message.content));
98 | }
99 |
100 | /**
101 | * 通知到达
102 | * @param notification
103 | * @private
104 | */
105 | _onNotification(notification) {
106 | console.log(notification)
107 | if(notification.clicked === true) {
108 | alert('app处于后台时收到通知' + JSON.stringify(notification));
109 | } else {
110 | alert('app处于前台时收到通知' + JSON.stringify(notification));
111 | }
112 | }
113 |
114 | /**
115 | * 获取初始通知(点击通知后)
116 | * @private
117 | */
118 | _getInitialNotification() {
119 | XGPush.getInitialNotification().then((result) => {
120 | alert(JSON.stringify(result));
121 | });
122 | }
123 |
124 | _enableDebug() {
125 | XGPush.enableDebug(!this.state.isDebug);
126 | }
127 |
128 | _isEnableDebug() {
129 | XGPush.isEnableDebug().then(result => {
130 | this.setState({
131 | isDebug: result
132 | });
133 | alert(result);
134 | });
135 | }
136 |
137 | _setApplicationIconBadgeNumber(number = 0) {
138 | XGPush.setApplicationIconBadgeNumber(number);
139 | }
140 |
141 | _getApplicationIconBadgeNumber() {
142 | XGPush.getApplicationIconBadgeNumber((number) => alert(number));
143 | }
144 |
145 | render() {
146 | return (
147 |
148 |
149 |
150 | getInitialNotification
151 |
152 |
153 | { this._enableDebug() }} underlayColor="#ddd">
154 |
155 | enableDebug
156 |
157 |
158 | { this._isEnableDebug() }} underlayColor="#ddd">
159 |
160 | isEnableDebug
161 |
162 |
163 | { this._setApplicationIconBadgeNumber(99) }} underlayColor="#ddd">
164 |
165 | setApplicationIconBadgeNumber: 99
166 |
167 |
168 | { this._getApplicationIconBadgeNumber() }} underlayColor="#ddd">
169 |
170 | getApplicationIconBadgeNumber
171 |
172 |
173 |
174 | );
175 | }
176 | }
177 |
178 | const styles = StyleSheet.create({
179 | container: {
180 | flex: 1,
181 | backgroundColor: '#fff',
182 | paddingTop: 20,
183 | },
184 | list: {
185 | marginTop: 15,
186 | backgroundColor: '#fff',
187 | },
188 | item: {
189 | height: 45,
190 | alignItems: 'center',
191 | justifyContent: 'center',
192 | borderBottomWidth: StyleSheet.hairlineWidth,
193 | borderBottomColor: '#efefef'
194 | },
195 | });
196 |
197 | export default Example;
198 |
--------------------------------------------------------------------------------
/example/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Sample React Native App
3 | * https://github.com/facebook/react-native
4 | * @flow
5 | */
6 |
7 | import React from 'react';
8 | import { AppRegistry } from 'react-native';
9 |
10 | import App from './app/index.js';
11 |
12 | AppRegistry.registerComponent('example', () => App);
13 |
--------------------------------------------------------------------------------
/example/ios/example-tvOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UIViewControllerBasedStatusBarAppearance
38 |
39 | NSLocationWhenInUseUsageDescription
40 |
41 | NSAppTransportSecurity
42 |
43 |
44 | NSExceptionDomains
45 |
46 | localhost
47 |
48 | NSExceptionAllowsInsecureHTTPLoads
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/example/ios/example-tvOSTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
52 |
53 |
58 |
59 |
61 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
79 |
80 |
81 |
82 |
92 |
94 |
100 |
101 |
102 |
103 |
104 |
105 |
111 |
113 |
119 |
120 |
121 |
122 |
124 |
125 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
62 |
68 |
69 |
70 |
71 |
72 |
78 |
79 |
80 |
81 |
82 |
83 |
94 |
96 |
102 |
103 |
104 |
105 |
106 |
107 |
113 |
115 |
121 |
122 |
123 |
124 |
126 |
127 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/example/ios/example/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | @interface AppDelegate : UIResponder
13 |
14 | @property (nonatomic, strong) UIWindow *window;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/example/ios/example/AppDelegate.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "AppDelegate.h"
11 |
12 | #import
13 | #import
14 | #import
15 | #import
16 |
17 | @implementation AppDelegate
18 |
19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
20 | {
21 | NSURL *jsCodeLocation;
22 | #ifdef DEBUG
23 | [[RCTBundleURLProvider sharedSettings] setJsLocation:@"192.168.0.154"];
24 | #endif
25 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
26 |
27 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
28 | moduleName:@"example"
29 | initialProperties:nil
30 | launchOptions:launchOptions];
31 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
32 |
33 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
34 | UIViewController *rootViewController = [UIViewController new];
35 | rootViewController.view = rootView;
36 | self.window.rootViewController = rootViewController;
37 | [self.window makeKeyAndVisible];
38 | // 统计消息推送的抵达情况
39 | [[XGPush defaultManager] reportXGNotificationInfo:launchOptions];
40 | return YES;
41 | }
42 |
43 | // Required to register for notifications
44 | - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
45 | {
46 | [XGPushManager didRegisterUserNotificationSettings:notificationSettings];
47 | }
48 |
49 | - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
50 | [XGPushManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
51 | }
52 |
53 | // Required for the registrationError event.
54 | - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
55 | NSLog(@"[XGPush] register APNS fail.\n[XGPush] reason : %@", error);
56 | [XGPushManager didFailToRegisterForRemoteNotificationsWithError:error];
57 | }
58 |
59 | // Required for the localNotification event.
60 | - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
61 | {
62 | [XGPushManager didReceiveLocalNotification:notification];
63 | }
64 |
65 | /**
66 | 收到静默消息的回调,通常此消息意味着有新数据可以读取(iOS 7.0+)
67 |
68 | @param application UIApplication 实例
69 | @param userInfo 推送时指定的参数
70 | @param completionHandler 完成回调
71 | */
72 | - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
73 | NSLog(@"[XGPush] receive slient Message");
74 | NSLog(@"[XGPush] userinfo %@", userInfo);
75 |
76 | [[XGPush defaultManager] reportXGNotificationInfo:userInfo];
77 | [XGPushManager didReceiveRemoteMessage:userInfo fetchCompletionHandler:completionHandler];
78 | }
79 |
80 |
81 |
82 |
83 | @end
84 |
--------------------------------------------------------------------------------
/example/ios/example/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | }
43 | ],
44 | "info" : {
45 | "version" : 1,
46 | "author" : "xcode"
47 | }
48 | }
--------------------------------------------------------------------------------
/example/ios/example/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/example/ios/example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | example
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | NSAppTransportSecurity
28 |
29 | NSExceptionDomains
30 |
31 | localhost
32 |
33 | NSExceptionAllowsInsecureHTTPLoads
34 |
35 |
36 |
37 |
38 | NSLocationWhenInUseUsageDescription
39 |
40 | UIBackgroundModes
41 |
42 | remote-notification
43 |
44 | UILaunchStoryboardName
45 | LaunchScreen
46 | UIRequiredDeviceCapabilities
47 |
48 | armv7
49 |
50 | UISupportedInterfaceOrientations
51 |
52 | UIInterfaceOrientationPortrait
53 | UIInterfaceOrientationLandscapeLeft
54 | UIInterfaceOrientationLandscapeRight
55 |
56 | UIViewControllerBasedStatusBarAppearance
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/example/ios/example/example.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | aps-environment
6 | development
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/example/main.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "AppDelegate.h"
13 |
14 | int main(int argc, char * argv[]) {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/example/ios/exampleTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/example/ios/exampleTests/exampleTests.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 | #import
12 |
13 | #import
14 | #import
15 |
16 | #define TIMEOUT_SECONDS 600
17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
18 |
19 | @interface exampleTests : XCTestCase
20 |
21 | @end
22 |
23 | @implementation exampleTests
24 |
25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
26 | {
27 | if (test(view)) {
28 | return YES;
29 | }
30 | for (UIView *subview in [view subviews]) {
31 | if ([self findSubviewInView:subview matching:test]) {
32 | return YES;
33 | }
34 | }
35 | return NO;
36 | }
37 |
38 | - (void)testRendersWelcomeScreen
39 | {
40 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
42 | BOOL foundElement = NO;
43 |
44 | __block NSString *redboxError = nil;
45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
46 | if (level >= RCTLogLevelError) {
47 | redboxError = message;
48 | }
49 | });
50 |
51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
54 |
55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
57 | return YES;
58 | }
59 | return NO;
60 | }];
61 | }
62 |
63 | RCTSetLogFunction(RCTDefaultLogFunction);
64 |
65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
67 | }
68 |
69 |
70 | @end
71 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "start": "node node_modules/react-native/local-cli/cli.js start",
7 | "test": "jest",
8 | "android": "node node_modules/react-native/local-cli/cli.js run-android",
9 | "ios": "node node_modules/react-native/local-cli/cli.js run-ios --simulator 'iPhone 8'",
10 | "bundle-android": "react-native bundle --entry-file index.js --bundle-output ./android/app/src/main/assets/index.android.bundle --assets-dest ./android/app/src/main/res --platform android --dev false",
11 | "bundle-ios": "react-native bundle --entry-file index.js --bundle-output ./ios/main.jsbundle --assets-dest ./ios --platform ios --dev false",
12 | "log-android": "react-native log-android"
13 | },
14 | "dependencies": {
15 | "react": "^16.3.1",
16 | "react-native": "^0.52.3",
17 | "react-native-xinge-push": "file:.."
18 | },
19 | "devDependencies": {
20 | "babel-jest": "^21.2.0",
21 | "babel-preset-react-native": "^4.0.0",
22 | "jest": "^21.2.1",
23 | "react-test-renderer": "^16.3.1"
24 | },
25 | "jest": {
26 | "preset": "react-native"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 信鸽推送
3 | * Created by Jeepeng on 16/8/3.
4 | */
5 |
6 | import {
7 | Platform,
8 | NativeModules,
9 | NativeEventEmitter,
10 | } from 'react-native';
11 |
12 | let { XGPushManager } = NativeModules;
13 | let XGNativeEventEmitter = new NativeEventEmitter(XGPushManager);
14 |
15 | let _handlers = new Map();
16 |
17 | const EventMapping = Platform.select({
18 | android: {
19 | register: 'remoteNotificationsRegistered',
20 | notification: 'remoteNotificationReceived',
21 | localNotification: 'localNotificationReceived',
22 | message: 'messageReceived'
23 | },
24 | ios: {
25 | register: 'remoteNotificationsRegistered',
26 | notification: 'remoteNotificationReceived',
27 | message: 'remoteMessageReceived',
28 | localNotification: 'localNotificationReceived',
29 | },
30 | });
31 |
32 | class XGPush {
33 |
34 | static init(accessId, accessKey) {
35 | let accessIdNum = Number(accessId);
36 | if (isNaN(accessIdNum)) {
37 | console.error(`[XGPush init] accessId is not a number!`);
38 | } else {
39 | if (Platform.OS === 'ios') {
40 | XGPushManager.startXGWithAppID(accessIdNum, accessKey);
41 | } else {
42 | XGPushManager.init(accessIdNum, accessKey);
43 | }
44 | }
45 | }
46 |
47 | static register(account) {
48 | if (Platform.OS === 'ios') {
49 | return XGPushManager.bindWithAccount(account);
50 | } else {
51 | return XGPushManager.registerPush();
52 | }
53 | }
54 |
55 | static setTag(tagName) {
56 | if (Platform.OS === 'ios') {
57 | return XGPushManager.bindWithTag(tagName);
58 | } else {
59 | return XGPushManager.setTag(tagName);
60 | }
61 | }
62 |
63 | static deleteTag(tagName) {
64 | if (Platform.OS === 'ios') {
65 | return XGPushManager.unbindWithTag(tagName);
66 | } else {
67 | return XGPushManager.deleteTag(tagName);
68 | }
69 | }
70 |
71 | static unRegister() {
72 | if (Platform.OS === 'ios') {
73 | return XGPushManager.stopXGNotification();
74 | } else {
75 | return XGPushManager.unregisterPush();
76 | }
77 | }
78 |
79 | static setApplicationIconBadgeNumber(number) {
80 | XGPushManager.setApplicationIconBadgeNumber(number);
81 | }
82 |
83 | static getApplicationIconBadgeNumber(callback) {
84 | XGPushManager.getApplicationIconBadgeNumber(callback);
85 | }
86 |
87 | static checkPermissions(callback) {
88 | if (Platform.OS === 'ios') {
89 | return XGPushManager.checkPermissions(callback);
90 | }
91 | }
92 |
93 | static getInitialNotification() {
94 | return XGPushManager.getInitialNotification();
95 | }
96 |
97 | static onLocalNotification(callback) {
98 | this.addEventListener('localNotification', callback)
99 | }
100 |
101 | /**
102 | * 透传消息 Android only
103 | */
104 | static onMessage(callback) {
105 | if (Platform.OS === 'android') {
106 | this.addEventListener('message', callback)
107 | }
108 | }
109 |
110 | static addEventListener(eventType, callback) {
111 | let event = EventMapping[eventType];
112 | if (!event) {
113 | console.warn('XGPush only supports `notification`, `register`, `message` ,and `localNotification` events');
114 | return;
115 | }
116 | let listener = XGNativeEventEmitter.addListener(event, (data) => {
117 | let result = data;
118 | if (eventType === 'register') {
119 | result = data['deviceToken'];
120 | }
121 | callback(result);
122 | });
123 | _handlers.set(callback, listener);
124 | }
125 |
126 | static removeEventListener(eventType, callback) {
127 | if (!EventMapping[eventType]) {
128 | console.warn('XGPush only supports `notification`, `register`, `message` and `localNotification` events');
129 | return;
130 | }
131 | let listener = _handlers.get(callback);
132 | if (listener) {
133 | listener.remove();
134 | _handlers.delete(callback);
135 | }
136 | }
137 |
138 | static enableDebug(isDebug = true) {
139 | if (Platform.OS === 'ios') {
140 | XGPushManager.setEnableDebug(isDebug);
141 | } else {
142 | XGPushManager.enableDebug(isDebug);
143 | }
144 | }
145 |
146 | static isEnableDebug() {
147 | return XGPushManager.isEnableDebug();
148 | }
149 |
150 | /**************************** android only ************************/
151 |
152 | /**
153 | * 获取设备的token,只有注册成功才能获取到正常的结果
154 | */
155 | static getToken() {
156 | if (Platform.OS === 'android') {
157 | return XGPushManager.getToken();
158 | } else {
159 | return Promise.resolve();
160 | }
161 | }
162 |
163 | /**
164 | * 设置上报通知栏是否关闭 默认打开
165 | */
166 | static setReportNotificationStatusEnable() {
167 | if (Platform.OS === 'android') {
168 | XGPushManager.setReportNotificationStatusEnable();
169 | }
170 | }
171 |
172 | /**
173 | * 设置上报APP 列表,用于智能推送 默认打开
174 | */
175 | static setReportApplistEnable() {
176 | if (Platform.OS === 'android') {
177 | XGPushManager.setReportApplistEnable();
178 | }
179 | }
180 |
181 | /**
182 | * 打开第三方推送(在 registerPush 之前调用)
183 | * @param isEnable
184 | */
185 | static enableOtherPush(isEnable = true) {
186 | if (Platform.OS === 'android') {
187 | XGPushManager.enableOtherPush(isEnable);
188 | }
189 | }
190 |
191 | /**
192 | * 打开华为通道debug模式
193 | * @param isDebug
194 | */
195 | static setHuaweiDebug(isDebug = true) {
196 | if (Platform.OS === 'android') {
197 | XGPushManager.setHuaweiDebug(isDebug);
198 | }
199 | }
200 |
201 | static initXiaomi(appId, appKey) {
202 | if (Platform.OS === 'android') {
203 | XGPushManager.initXiaomi(appId, appKey);
204 | }
205 | }
206 |
207 | static initMeizu(appId, appKey) {
208 | if (Platform.OS === 'android') {
209 | XGPushManager.initMeizu(appId, appKey);
210 | }
211 | }
212 |
213 | static initFcm(isEnable = true){
214 | if(Platform.OS === 'android'){
215 | XGPushManager.initFcm(isEnable);
216 | }
217 | }
218 |
219 |
220 | /**************************** ios only ************************/
221 |
222 |
223 | }
224 |
225 | export default XGPush;
226 |
--------------------------------------------------------------------------------
/ios/SDK/XGPush.h:
--------------------------------------------------------------------------------
1 | //
2 | // 信鸽核心接口
3 | // XG-SDK
4 | //
5 | // Created by xiangchen on 13-10-18.
6 | // Update by uweiyuan on 4/08/17.
7 | // Copyright (c) 2013年 XG. All rights reserved.
8 | //
9 |
10 | #import
11 | #import
12 |
13 | @class CLLocation;
14 |
15 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
16 | #import
17 | #endif
18 |
19 | /**
20 | @brief 点击行为对象的属性配置
21 |
22 | - XGNotificationActionOptionNone: 无
23 | - XGNotificationActionOptionAuthenticationRequired: 需要认证的选项
24 | - XGNotificationActionOptionDestructive: 具有破坏意义的选项
25 | - XGNotificationActionOptionForeground: 打开应用的选项
26 | */
27 | typedef NS_ENUM(NSUInteger, XGNotificationActionOptions) {
28 | XGNotificationActionOptionNone = (0),
29 | XGNotificationActionOptionAuthenticationRequired = (1 << 0),
30 | XGNotificationActionOptionDestructive = (1 << 1),
31 | XGNotificationActionOptionForeground = (1 << 2)
32 | };
33 |
34 | /**
35 | * @brief 定义了一个可以在通知栏中点击的事件对象
36 | */
37 | @interface XGNotificationAction : NSObject
38 |
39 | /**
40 | @brief 在通知消息中创建一个可以点击的事件行为
41 |
42 | @param identifier 行为唯一标识
43 | @param title 行为名称
44 | @param options 行为支持的选项
45 | @return 行为对象
46 | @note 通知栏带有点击事件的特性,只有在iOS8+以上支持,iOS 8 or earlier的版本,此方法返回空
47 | */
48 | + (nullable id)actionWithIdentifier:(nonnull NSString *)identifier title:(nonnull NSString *)title options:(XGNotificationActionOptions)options;
49 |
50 | /**
51 | @brief 点击行为的标识
52 | */
53 | @property (nullable, nonatomic, copy, readonly) NSString *identifier;
54 |
55 | /**
56 | @brief 点击行为的标题
57 | */
58 | @property (nullable, nonatomic, copy, readonly) NSString *title;
59 |
60 | /**
61 | @brief 点击行为的特性
62 | */
63 | @property (readonly, nonatomic) XGNotificationActionOptions options;
64 |
65 | @end
66 |
67 |
68 | /**
69 | @brief 分类对象的属性配置
70 |
71 | - XGNotificationCategoryOptionNone: 无
72 | - XGNotificationCategoryOptionCustomDismissAction: 发送消失事件给UNUserNotificationCenter(iOS 10 or later)对象
73 | - XGNotificationCategoryOptionAllowInCarPlay: 允许CarPlay展示此类型的消息
74 | */
75 | typedef NS_OPTIONS(NSUInteger, XGNotificationCategoryOptions) {
76 | XGNotificationCategoryOptionNone = (0),
77 | XGNotificationCategoryOptionCustomDismissAction = (1 << 0),
78 | XGNotificationCategoryOptionAllowInCarPlay = (1 << 1)
79 | };
80 |
81 |
82 | /**
83 | * 通知栏中消息指定的分类,分类主要用来管理一组关联的Action,以实现不同分类对应不同的Actions
84 | */
85 | @interface XGNotificationCategory : NSObject
86 |
87 |
88 | /**
89 | @brief 创建分类对象,用以管理通知栏的Action对象
90 |
91 | @param identifier 分类对象的标识
92 | @param actions 当前分类拥有的行为对象组
93 | @param intentIdentifiers 用以表明可以通过Siri识别的标识
94 | @param options 分类的特性
95 | @return 管理点击行为的分类对象
96 | @note 通知栏带有点击事件的特性,只有在iOS8+以上支持,iOS 8 or earlier的版本,此方法返回空
97 | */
98 | + (nullable id)categoryWithIdentifier:(nonnull NSString *)identifier actions:(nullable NSArray *)actions intentIdentifiers:(nullable NSArray *)intentIdentifiers options:(XGNotificationCategoryOptions)options;
99 |
100 | /**
101 | @brief 分类对象的标识
102 | */
103 | @property (nonnull, readonly, copy, nonatomic) NSString *identifier;
104 |
105 | /**
106 | @brief 分类对象拥有的点击行为组
107 | */
108 | @property (nonnull, readonly, copy, nonatomic) NSArray *actions;
109 |
110 | /**
111 | @brief 可用以Siri意图的标识组
112 | */
113 | @property (nullable, readonly, copy, nonatomic) NSArray *intentIdentifiers;
114 |
115 | /**
116 | @brief 分类的特性
117 | */
118 | @property (readonly, nonatomic) XGNotificationCategoryOptions options;
119 |
120 | @end
121 |
122 | /**
123 | @brief 注册通知支持的类型
124 |
125 | - XGUserNotificationTypeNone: 无
126 | - XGUserNotificationTypeBadge: 支持应用角标
127 | - XGUserNotificationTypeSound: 支持铃声
128 | - XGUserNotificationTypeAlert: 支持弹框
129 | - XGUserNotificationTypeCarPlay: 支持CarPlay,iOS 10.0+
130 | - XGUserNotificationTypeCriticalAlert: 支持紧急提醒播放声音, iOS 12.0+
131 | - XGUserNotificationTypeProvidesAppNotificationSettings: 让系统在应用内通知设置中显示按钮, iOS 12.0+
132 | - XGUserNotificationTypeProvisional: 能够将非中断通知临时发布到 Notification Center, iOS 12.0+
133 | - XGUserNotificationTypeNewsstandContentAvailability: 支持 Newsstand, iOS 3.0–8.0
134 | */
135 | typedef NS_OPTIONS(NSUInteger, XGUserNotificationTypes) {
136 | XGUserNotificationTypeNone = (0),
137 | XGUserNotificationTypeBadge = (1 << 0),
138 | XGUserNotificationTypeSound = (1 << 1),
139 | XGUserNotificationTypeAlert = (1 << 2),
140 | XGUserNotificationTypeCarPlay = (1 << 3),
141 | XGUserNotificationTypeCriticalAlert = (1 << 4),
142 | XGUserNotificationTypeProvidesAppNotificationSettings = (1 << 5),
143 | XGUserNotificationTypeProvisional = (1 << 6),
144 | XGUserNotificationTypeNewsstandContentAvailability = (1 << 3)
145 | };
146 |
147 | /**
148 | @brief 管理推送消息通知栏的样式和特性
149 | */
150 | @interface XGNotificationConfigure : NSObject
151 |
152 | /**
153 | @brief 配置通知栏对象,主要是为了配置消息通知的样式和行为特性
154 |
155 | @param categories 通知栏中支持的分类集合
156 | @param types 注册通知的样式
157 | @return 配置对象
158 | */
159 | + (nullable instancetype)configureNotificationWithCategories:(nullable NSSet *)categories types:(XGUserNotificationTypes)types;
160 |
161 | - (nonnull instancetype)init NS_UNAVAILABLE;
162 | /**
163 | @brief 返回消息通知栏配置对象
164 | */
165 | @property (readonly, nullable, strong, nonatomic) NSSet *categories;
166 |
167 |
168 | /**
169 | @brief 返回注册推送的样式类型
170 | */
171 | @property (readonly, nonatomic) XGUserNotificationTypes types;
172 |
173 | /**
174 | @brief 默认的注册推送的样式类型
175 | */
176 | @property (readonly, nonatomic) XGUserNotificationTypes defaultTypes;
177 |
178 | @end
179 |
180 |
181 | /**
182 | @brief 设备token绑定的类型,绑定指定类型之后,就可以在信鸽前端按照指定的类型进行指定范围的推送
183 |
184 | - XGPushTokenBindTypeNone: 当前设备token不绑定任何类型,可以使用token单推,或者是全量推送(3.2.0+ 不推荐使用 )
185 | - XGPushTokenBindTypeAccount: 当前设备token与账号绑定之后,可以使用账号推送
186 | - XGPushTokenBindTypeTag: 当前设备token与指定标签绑定之后,可以使用标签推送
187 | */
188 | typedef NS_ENUM(NSUInteger, XGPushTokenBindType) {
189 | XGPushTokenBindTypeNone = (0),
190 | XGPushTokenBindTypeAccount = (1 << 0),
191 | XGPushTokenBindTypeTag = (1 << 1)
192 | };
193 |
194 | /**
195 | @brief 定义了一组关于设备token绑定,解绑账号和标签的回调方法,用以监控绑定和解绑的情况
196 | */
197 | @protocol XGPushTokenManagerDelegate
198 |
199 | @optional
200 |
201 | /**
202 | @brief 监控token对象绑定的情况
203 |
204 | @param identifier token对象绑定的标识
205 | @param type token对象绑定的类型
206 | @param error token对象绑定的结果信息
207 | */
208 | - (void)xgPushDidBindWithIdentifier:(nonnull NSString *)identifier type:(XGPushTokenBindType)type error:(nullable NSError *)error;
209 |
210 | /**
211 | @brief 监控token对象解绑的情况
212 |
213 | @param identifier token对象解绑的标识
214 | @param type token对象解绑的类型
215 | @param error token对象解绑的结果信息
216 | */
217 | - (void)xgPushDidUnbindWithIdentifier:(nonnull NSString *)identifier type:(XGPushTokenBindType)type error:(nullable NSError *)error;
218 |
219 | /**
220 | @brief 监控token对象identifiers绑定的情况
221 |
222 | @param identifiers token对象绑定的标识
223 | @param type token对象绑定的类型
224 | @param error token对象绑定的结果信息
225 | */
226 | - (void)xgPushDidBindWithIdentifiers:(nonnull NSArray *)identifiers type:(XGPushTokenBindType)type error:(nullable NSError *)error;
227 |
228 | /**
229 | @brief 监控token对象identifiers解绑的情况
230 |
231 | @param identifiers token对象解绑的标识
232 | @param type token对象解绑的类型
233 | @param error token对象解绑的结果信息
234 | */
235 | - (void)xgPushDidUnbindWithIdentifiers:(nonnull NSArray *)identifiers type:(XGPushTokenBindType)type error:(nullable NSError *)error;
236 |
237 | /**
238 | @brief 监控token对象更新已绑定标识的情况
239 |
240 | @param identifiers token对象更新后的标识
241 | @param type token对象更新类型
242 | @param error token对象更新标识的结果信息
243 | */
244 | - (void)xgPushDidUpdatedBindedIdentifiers:(nonnull NSArray *)identifiers bindType:(XGPushTokenBindType)type error:(nullable NSError *)error;
245 |
246 |
247 | /**
248 | @brief 监控清除token对象绑定标识的情况
249 |
250 | @param type token对象清除的类型
251 | @param error token对象清除标识的结果信息
252 | */
253 | - (void)xgPushDidClearAllIdentifiers:(XGPushTokenBindType)type error:(nullable NSError *)error;
254 |
255 |
256 | @end
257 |
258 | @interface XGPushTokenManager : NSObject
259 |
260 | /**
261 | @brief 创建设备token的管理对象,用来管理token的绑定与解绑操作
262 |
263 | @return 设备token管理对象
264 | @note 此类的 APIs 调用都是以 Token 在信鸽服务上完成注册为前提
265 | */
266 |
267 | + (nonnull instancetype)defaultTokenManager;
268 |
269 | - (nonnull instancetype)init NS_UNAVAILABLE;
270 | /**
271 | @brief 设备token管理操作的代理对象
272 | */
273 | @property (weak, nonatomic, nullable) id delegate;
274 |
275 | /**
276 | @brief 返回当前设备token的字符串
277 | */
278 | @property (copy, nonatomic, nullable, readonly) NSString *deviceTokenString;
279 |
280 | /**
281 | @brief 为token对象设置绑定类型和标识
282 |
283 | @param identifier 指定绑定标识
284 | @param type 指定绑定类型
285 | */
286 | - (void)bindWithIdentifier:(nonnull NSString *)identifier type:(XGPushTokenBindType)type;
287 |
288 | /**
289 | @brief 根据类型和标识为token对象解绑
290 |
291 | @param identifier 指定解绑标识
292 | @param type 指定解绑类型
293 | @note 若需要解绑全部标签,建议使用 removeAllTags: 接口
294 | */
295 | - (void)unbindWithIdentifer:(nonnull NSString *)identifier type:(XGPushTokenBindType)type;
296 |
297 | /**
298 | @brief 根据指定类型查询当前token对象绑定的标识
299 |
300 | @param type 指定绑定类型
301 | @return 当前token对象绑定的标识
302 | */
303 | - (nullable NSArray *)identifiersWithType:(XGPushTokenBindType)type;
304 |
305 | /**
306 | @brief 为token对象设置绑定类型和标识
307 |
308 | @param identifiers 指定绑定标识,标签字符串不允许有空格或者是tab字符
309 | @param type 指定绑定类型
310 | @note 对于账号操作,需要使用json数组,例如:
311 | [
312 | {"account" : "account1", "account_type" : 1},
313 | {"account" : "account2","account_type" : 0}
314 | ]
315 | 账号类型,请参照: http://xg.qq.com/docs/server_api/v3/push_api_v3.html#账号类型
316 | */
317 | - (void)bindWithIdentifiers:(nonnull NSArray *)identifiers type:(XGPushTokenBindType)type;
318 |
319 | /**
320 | @brief 根据类型和标识为token对象解绑
321 |
322 | @param identifiers 指定解绑标识,标签字符串不允许有空格或者是tab字符
323 | @param type 指定解绑类型
324 | @note 标签字符串不允许有空格或者是tab字符;对于账号操作,需要使用json数组,例如:
325 | [
326 | {"account" : "account1", "account_type" : 1},
327 | {"account" : "account2","account_type" : 0}
328 | ]
329 | 账号类型,请参照: http://xg.qq.com/docs/server_api/v3/push_api_v3.html#账号类型
330 | */
331 | - (void)unbindWithIdentifers:(nonnull NSArray *)identifiers type:(XGPushTokenBindType)type;
332 |
333 | /**
334 | @brief 根据类型,覆盖原有的标识;若之前没有绑定标识,则会执行新增标识
335 |
336 | @param identifiers 标签标识字符串数组,标签字符串不允许有空格或者是tab字符
337 | @param type 标识类型
338 | @note 若指定为标签类型,此接口会将当前 Token 对应的旧有的标签全部替换为当前的标签;若指定账号类型,对于账号操作,则需要使用json数组,例如:
339 | [
340 | {"account" : "account1", "account_type" : 1},
341 | {"account" : "account2","account_type" : 0}
342 | ]
343 | 账号类型,请参照: http://xg.qq.com/docs/server_api/v3/push_api_v3.html#账号类型
344 | */
345 | - (void)updateBindedIdentifiers:(nonnull NSArray *)identifiers bindType:(XGPushTokenBindType)type;
346 |
347 | /**
348 | @brief 根据标识类型,清除所有标识
349 |
350 | @param type 标识类型
351 | */
352 | - (void)clearAllIdentifiers:(XGPushTokenBindType)type;
353 |
354 |
355 | @end
356 |
357 |
358 | /**
359 | @brief 监控信鸽服务启动和设备token注册的一组方法
360 | */
361 | @protocol XGPushDelegate
362 |
363 | @optional
364 |
365 | - (void)xgPushDidReceiveRemoteNotification:(nonnull id)notification withCompletionHandler:(nullable void (^)(NSUInteger))completionHandler;
366 |
367 |
368 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
369 | /**
370 | @brief 处理iOS 10 UNUserNotification.framework的对应的方法
371 |
372 | @param center [UNUserNotificationCenter currentNotificationCenter]
373 | @param notification 通知对象
374 | @param completionHandler 回调对象,必须调用
375 | */
376 | - (void)xgPushUserNotificationCenter:(nonnull UNUserNotificationCenter *)center willPresentNotification:(nullable UNNotification *)notification withCompletionHandler:(nonnull void (^)(UNNotificationPresentationOptions options))completionHandler __IOS_AVAILABLE(10.0);
377 |
378 | /**
379 | @brief 处理iOS 10 UNUserNotification.framework的对应的方法
380 |
381 | @param center [UNUserNotificationCenter currentNotificationCenter]
382 | @param response 用户对通知消息的响应对象
383 | @param completionHandler 回调对象,必须调用
384 | */
385 | - (void)xgPushUserNotificationCenter:(nonnull UNUserNotificationCenter *)center didReceiveNotificationResponse:(nullable UNNotificationResponse *)response withCompletionHandler:(nonnull void (^)(void))completionHandler __IOS_AVAILABLE(10.0);
386 |
387 | #endif
388 |
389 | /**
390 | @brief 监控信鸽推送服务地启动情况
391 |
392 | @param isSuccess 信鸽推送是否启动成功
393 | @param error 信鸽推送启动错误的信息
394 | */
395 | - (void)xgPushDidFinishStart:(BOOL)isSuccess error:(nullable NSError *)error;
396 |
397 | /**
398 | @brief 监控信鸽服务的终止情况
399 |
400 | @param isSuccess 信鸽推送是否终止
401 | @param error 信鸽推动终止错误的信息
402 | */
403 | - (void)xgPushDidFinishStop:(BOOL)isSuccess error:(nullable NSError *)error;
404 |
405 |
406 | /**
407 | @brief 监控信鸽服务上报推送消息的情况
408 |
409 | @param isSuccess 上报是否成功
410 | @param error 上报失败的信息
411 | */
412 | - (void)xgPushDidReportNotification:(BOOL)isSuccess error:(nullable NSError *)error;
413 |
414 |
415 | /**
416 | @brief 监控设置信鸽服务器下发角标的情况
417 |
418 | @param isSuccess isSuccess 上报是否成功
419 | @param error 设置失败的信息
420 | */
421 | - (void)xgPushDidSetBadge:(BOOL)isSuccess error:(nullable NSError *)error;
422 |
423 | /**
424 | @brief 设备token注册信鸽服务的回调
425 |
426 | @param deviceToken 当前设备的token
427 | @param error 错误信息
428 | */
429 | - (void)xgPushDidRegisteredDeviceToken:(nullable NSString *)deviceToken error:(nullable NSError *)error;
430 |
431 | @end
432 |
433 | /**
434 | @brief 管理信鸽推送服务的对象,负责注册推送权限、消息的管理、调试模式的开关设置等
435 | */
436 | @interface XGPush : NSObject
437 |
438 | #pragma mark - 初始化相关
439 |
440 | /**
441 | @brief 获取信鸽推送管理的单例对象
442 |
443 | @return 信鸽推送对象
444 | */
445 | + (nonnull instancetype)defaultManager;
446 |
447 | /**
448 | @brief 关于信鸽推送SDK接口协议的对象
449 | */
450 | @property (weak, nonatomic, nullable, readonly) id delegate;
451 |
452 |
453 | /**
454 | @brief 信鸽推送管理对象,管理推送的配置选项,例如,注册推送的样式
455 | */
456 | @property (nullable, strong, nonatomic) XGNotificationConfigure *notificationConfigure;
457 |
458 |
459 | /**
460 | @brief 这个开关表明是否打印信鸽SDK的日志信息
461 | */
462 | @property (assign, getter=isEnableDebug) BOOL enableDebug;
463 |
464 | /**
465 | @brief 返回信鸽推送服务的状态
466 | */
467 | @property (assign, readonly) BOOL xgNotificationStatus __deprecated_msg("XG SDK 3.3+, instead, you can use deviceTokenDidRegisteredXGService property");
468 |
469 |
470 | /**
471 | @brief 设备在信鸽服务中的是否处于注册状态
472 | */
473 | @property (assign, readonly) BOOL deviceDidRegisteredXG;
474 |
475 | /**
476 | @brief 管理应用角标
477 | */
478 | @property (nonatomic) NSInteger xgApplicationBadgeNumber;
479 |
480 | /**
481 | @brief 通过使用在信鸽官网注册的应用的信息,启动信鸽推送服务
482 |
483 | @param appID 通过前台申请的应用ID
484 | @param appKey 通过前台申请的appKey
485 | @param delegate 回调对象
486 | @note 接口所需参数必须要正确填写,反之信鸽服务将不能正确为应用推送消息
487 | */
488 | - (void)startXGWithAppID:(uint32_t)appID appKey:(nonnull NSString *)appKey delegate:(nullable id)delegate;
489 |
490 | /**
491 | @brief 停止信鸽推送服务
492 | @note 调用此方法将导致当前设备不再接受信鸽服务推送的消息.如果再次需要接收信鸽服务的消息推送,则必须需要再次调用startXG:withAppKey:delegate:方法重启信鸽推送服务
493 | */
494 | - (void)stopXGNotification;
495 |
496 | /**
497 | @brief 上报应用收到的推送信息,以便信鸽服务能够统计相关数据,包括但不限于:1.推送消息被点击的次数,2.消息曝光的次数
498 |
499 | @param info 应用接收到的推送消息对象的内容
500 | @note 请在实现application delegate 的 application:didFinishLaunchingWithOptions:或者application:didReceiveRemoteNotification:的方法中调用此接口,参数就使用这两个方法中的NSDictionaryl类型的参数即可,从而完成推送消息的数据统计
501 | */
502 | - (void)reportXGNotificationInfo:(nonnull NSDictionary *)info;
503 |
504 | /**
505 | @brief 上报地理位置信息
506 |
507 | @param latitude 纬度
508 | @param longitude 经度
509 | */
510 | - (void)reportLocationWithLatitude:(double)latitude longitude:(double)longitude;
511 |
512 | /**
513 | @brief 上报当前App角标数到信鸽服务器
514 |
515 | @param badgeNumber 应用的角标数
516 | @note 此接口是为了实现角标+1的功能,服务器会在这个数值基础上进行角标数新增的操作,调用成功之后,会覆盖之前值
517 | */
518 | - (void)setBadge:(NSInteger)badgeNumber;
519 |
520 | /**
521 | @brief 上报推送消息的用户行为
522 |
523 | @param identifier 用户行为标识
524 | @note 此接口即统计推送消息中开发者预先设置或者是系统预置的行为标识,可以了解到用户是如何处理推送消息的,又统计消息的点击次数
525 | */
526 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
527 | - (void)reportXGNotificationResponse:(nullable UNNotificationResponse *)response __IOS_AVAILABLE(10.0);
528 | #endif
529 |
530 | /**
531 | @brief 查询设备通知权限是否被用户允许
532 |
533 | @param handler 查询结果的返回方法
534 | @note iOS 10 or later 回调是异步地执行
535 | */
536 | - (void)deviceNotificationIsAllowed:(nonnull void (^)(BOOL isAllowed))handler;
537 |
538 | /**
539 | @brief 查看SDK的版本
540 |
541 | @return sdk版本号
542 | */
543 | - (nonnull NSString *)sdkVersion;
544 |
545 | @end
546 |
547 |
--------------------------------------------------------------------------------
/ios/XGPush.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2D9EBB202345D36200E0F598 /* libXG-SDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D9EBB1F2345D36200E0F598 /* libXG-SDK.a */; };
11 | C50FF02A1D54262A00CEF3D0 /* XGPushManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C50FF0291D54262A00CEF3D0 /* XGPushManager.m */; };
12 | /* End PBXBuildFile section */
13 |
14 | /* Begin PBXCopyFilesBuildPhase section */
15 | C50FF0221D54262A00CEF3D0 /* Copy Files */ = {
16 | isa = PBXCopyFilesBuildPhase;
17 | buildActionMask = 2147483647;
18 | dstPath = "include/$(PRODUCT_NAME)";
19 | dstSubfolderSpec = 16;
20 | files = (
21 | );
22 | name = "Copy Files";
23 | runOnlyForDeploymentPostprocessing = 0;
24 | };
25 | /* End PBXCopyFilesBuildPhase section */
26 |
27 | /* Begin PBXFileReference section */
28 | 2D9EBB1F2345D36200E0F598 /* libXG-SDK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libXG-SDK.a"; sourceTree = ""; };
29 | C50FF0241D54262A00CEF3D0 /* libXGPush.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libXGPush.a; sourceTree = BUILT_PRODUCTS_DIR; };
30 | C50FF0271D54262A00CEF3D0 /* XGPushManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XGPushManager.h; sourceTree = ""; };
31 | C50FF0291D54262A00CEF3D0 /* XGPushManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XGPushManager.m; sourceTree = ""; };
32 | C5D48E311D5428D2004BD09A /* XGPush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XGPush.h; path = SDK/XGPush.h; sourceTree = ""; };
33 | C5D48E761D54731F004BD09A /* libReact.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libReact.a; path = "../../react-native/React/build/Debug-iphoneos/libReact.a"; sourceTree = ""; };
34 | /* End PBXFileReference section */
35 |
36 | /* Begin PBXFrameworksBuildPhase section */
37 | C50FF0211D54262A00CEF3D0 /* Frameworks */ = {
38 | isa = PBXFrameworksBuildPhase;
39 | buildActionMask = 2147483647;
40 | files = (
41 | 2D9EBB202345D36200E0F598 /* libXG-SDK.a in Frameworks */,
42 | );
43 | runOnlyForDeploymentPostprocessing = 0;
44 | };
45 | /* End PBXFrameworksBuildPhase section */
46 |
47 | /* Begin PBXGroup section */
48 | C50FF01B1D54262A00CEF3D0 = {
49 | isa = PBXGroup;
50 | children = (
51 | C5D48E321D5428DE004BD09A /* Frameworks */,
52 | C5D48E2F1D5428C1004BD09A /* SDK */,
53 | C50FF0261D54262A00CEF3D0 /* XGPush */,
54 | C50FF0251D54262A00CEF3D0 /* Products */,
55 | );
56 | sourceTree = "";
57 | };
58 | C50FF0251D54262A00CEF3D0 /* Products */ = {
59 | isa = PBXGroup;
60 | children = (
61 | C50FF0241D54262A00CEF3D0 /* libXGPush.a */,
62 | );
63 | name = Products;
64 | sourceTree = "";
65 | };
66 | C50FF0261D54262A00CEF3D0 /* XGPush */ = {
67 | isa = PBXGroup;
68 | children = (
69 | C50FF0271D54262A00CEF3D0 /* XGPushManager.h */,
70 | C50FF0291D54262A00CEF3D0 /* XGPushManager.m */,
71 | );
72 | path = XGPush;
73 | sourceTree = "";
74 | };
75 | C5D48E2F1D5428C1004BD09A /* SDK */ = {
76 | isa = PBXGroup;
77 | children = (
78 | C5D48E311D5428D2004BD09A /* XGPush.h */,
79 | );
80 | name = SDK;
81 | sourceTree = "";
82 | };
83 | C5D48E321D5428DE004BD09A /* Frameworks */ = {
84 | isa = PBXGroup;
85 | children = (
86 | 2D9EBB1F2345D36200E0F598 /* libXG-SDK.a */,
87 | C5D48E761D54731F004BD09A /* libReact.a */,
88 | );
89 | name = Frameworks;
90 | sourceTree = "";
91 | };
92 | /* End PBXGroup section */
93 |
94 | /* Begin PBXNativeTarget section */
95 | C50FF0231D54262A00CEF3D0 /* XGPush */ = {
96 | isa = PBXNativeTarget;
97 | buildConfigurationList = C50FF02D1D54262A00CEF3D0 /* Build configuration list for PBXNativeTarget "XGPush" */;
98 | buildPhases = (
99 | C50FF0201D54262A00CEF3D0 /* Sources */,
100 | C50FF0211D54262A00CEF3D0 /* Frameworks */,
101 | C50FF0221D54262A00CEF3D0 /* Copy Files */,
102 | );
103 | buildRules = (
104 | );
105 | dependencies = (
106 | );
107 | name = XGPush;
108 | productName = RCTXGPush;
109 | productReference = C50FF0241D54262A00CEF3D0 /* libXGPush.a */;
110 | productType = "com.apple.product-type.library.static";
111 | };
112 | /* End PBXNativeTarget section */
113 |
114 | /* Begin PBXProject section */
115 | C50FF01C1D54262A00CEF3D0 /* Project object */ = {
116 | isa = PBXProject;
117 | attributes = {
118 | LastUpgradeCheck = 0730;
119 | ORGANIZATIONNAME = Jeepeng;
120 | TargetAttributes = {
121 | C50FF0231D54262A00CEF3D0 = {
122 | CreatedOnToolsVersion = 7.3.1;
123 | };
124 | };
125 | };
126 | buildConfigurationList = C50FF01F1D54262A00CEF3D0 /* Build configuration list for PBXProject "XGPush" */;
127 | compatibilityVersion = "Xcode 3.2";
128 | developmentRegion = English;
129 | hasScannedForEncodings = 0;
130 | knownRegions = (
131 | English,
132 | en,
133 | );
134 | mainGroup = C50FF01B1D54262A00CEF3D0;
135 | productRefGroup = C50FF0251D54262A00CEF3D0 /* Products */;
136 | projectDirPath = "";
137 | projectRoot = "";
138 | targets = (
139 | C50FF0231D54262A00CEF3D0 /* XGPush */,
140 | );
141 | };
142 | /* End PBXProject section */
143 |
144 | /* Begin PBXSourcesBuildPhase section */
145 | C50FF0201D54262A00CEF3D0 /* Sources */ = {
146 | isa = PBXSourcesBuildPhase;
147 | buildActionMask = 2147483647;
148 | files = (
149 | C50FF02A1D54262A00CEF3D0 /* XGPushManager.m in Sources */,
150 | );
151 | runOnlyForDeploymentPostprocessing = 0;
152 | };
153 | /* End PBXSourcesBuildPhase section */
154 |
155 | /* Begin XCBuildConfiguration section */
156 | C50FF02B1D54262A00CEF3D0 /* Debug */ = {
157 | isa = XCBuildConfiguration;
158 | buildSettings = {
159 | ALWAYS_SEARCH_USER_PATHS = NO;
160 | CLANG_ANALYZER_NONNULL = YES;
161 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
162 | CLANG_CXX_LIBRARY = "libc++";
163 | CLANG_ENABLE_MODULES = YES;
164 | CLANG_ENABLE_OBJC_ARC = YES;
165 | CLANG_WARN_BOOL_CONVERSION = YES;
166 | CLANG_WARN_CONSTANT_CONVERSION = YES;
167 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
168 | CLANG_WARN_EMPTY_BODY = YES;
169 | CLANG_WARN_ENUM_CONVERSION = YES;
170 | CLANG_WARN_INT_CONVERSION = YES;
171 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
172 | CLANG_WARN_UNREACHABLE_CODE = YES;
173 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
174 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
175 | COPY_PHASE_STRIP = NO;
176 | DEBUG_INFORMATION_FORMAT = dwarf;
177 | ENABLE_STRICT_OBJC_MSGSEND = YES;
178 | ENABLE_TESTABILITY = YES;
179 | GCC_C_LANGUAGE_STANDARD = gnu99;
180 | GCC_DYNAMIC_NO_PIC = NO;
181 | GCC_NO_COMMON_BLOCKS = YES;
182 | GCC_OPTIMIZATION_LEVEL = 0;
183 | GCC_PREPROCESSOR_DEFINITIONS = (
184 | "DEBUG=1",
185 | "$(inherited)",
186 | );
187 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
188 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
189 | GCC_WARN_UNDECLARED_SELECTOR = YES;
190 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
191 | GCC_WARN_UNUSED_FUNCTION = YES;
192 | GCC_WARN_UNUSED_VARIABLE = YES;
193 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
194 | MTL_ENABLE_DEBUG_INFO = YES;
195 | ONLY_ACTIVE_ARCH = YES;
196 | SDKROOT = iphoneos;
197 | };
198 | name = Debug;
199 | };
200 | C50FF02C1D54262A00CEF3D0 /* Release */ = {
201 | isa = XCBuildConfiguration;
202 | buildSettings = {
203 | ALWAYS_SEARCH_USER_PATHS = NO;
204 | CLANG_ANALYZER_NONNULL = YES;
205 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
206 | CLANG_CXX_LIBRARY = "libc++";
207 | CLANG_ENABLE_MODULES = YES;
208 | CLANG_ENABLE_OBJC_ARC = YES;
209 | CLANG_WARN_BOOL_CONVERSION = YES;
210 | CLANG_WARN_CONSTANT_CONVERSION = YES;
211 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
212 | CLANG_WARN_EMPTY_BODY = YES;
213 | CLANG_WARN_ENUM_CONVERSION = YES;
214 | CLANG_WARN_INT_CONVERSION = YES;
215 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
216 | CLANG_WARN_UNREACHABLE_CODE = YES;
217 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
218 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
219 | COPY_PHASE_STRIP = NO;
220 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
221 | ENABLE_NS_ASSERTIONS = NO;
222 | ENABLE_STRICT_OBJC_MSGSEND = YES;
223 | GCC_C_LANGUAGE_STANDARD = gnu99;
224 | GCC_NO_COMMON_BLOCKS = YES;
225 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
226 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
227 | GCC_WARN_UNDECLARED_SELECTOR = YES;
228 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
229 | GCC_WARN_UNUSED_FUNCTION = YES;
230 | GCC_WARN_UNUSED_VARIABLE = YES;
231 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
232 | MTL_ENABLE_DEBUG_INFO = NO;
233 | SDKROOT = iphoneos;
234 | VALIDATE_PRODUCT = YES;
235 | };
236 | name = Release;
237 | };
238 | C50FF02E1D54262A00CEF3D0 /* Debug */ = {
239 | isa = XCBuildConfiguration;
240 | buildSettings = {
241 | HEADER_SEARCH_PATHS = (
242 | "$(inherited)",
243 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
244 | "$(SRCROOT)/../../react-native/React/**",
245 | );
246 | LIBRARY_SEARCH_PATHS = (
247 | "$(inherited)",
248 | "$(PROJECT_DIR)/SDK/**",
249 | "$(PROJECT_DIR)",
250 | );
251 | OTHER_LDFLAGS = "-ObjC";
252 | PRODUCT_NAME = XGPush;
253 | SKIP_INSTALL = YES;
254 | };
255 | name = Debug;
256 | };
257 | C50FF02F1D54262A00CEF3D0 /* Release */ = {
258 | isa = XCBuildConfiguration;
259 | buildSettings = {
260 | HEADER_SEARCH_PATHS = (
261 | "$(inherited)",
262 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
263 | "$(SRCROOT)/../../react-native/React/**",
264 | );
265 | LIBRARY_SEARCH_PATHS = (
266 | "$(inherited)",
267 | "$(PROJECT_DIR)/SDK/**",
268 | "$(PROJECT_DIR)",
269 | );
270 | OTHER_LDFLAGS = "-ObjC";
271 | PRODUCT_NAME = XGPush;
272 | SKIP_INSTALL = YES;
273 | };
274 | name = Release;
275 | };
276 | /* End XCBuildConfiguration section */
277 |
278 | /* Begin XCConfigurationList section */
279 | C50FF01F1D54262A00CEF3D0 /* Build configuration list for PBXProject "XGPush" */ = {
280 | isa = XCConfigurationList;
281 | buildConfigurations = (
282 | C50FF02B1D54262A00CEF3D0 /* Debug */,
283 | C50FF02C1D54262A00CEF3D0 /* Release */,
284 | );
285 | defaultConfigurationIsVisible = 0;
286 | defaultConfigurationName = Release;
287 | };
288 | C50FF02D1D54262A00CEF3D0 /* Build configuration list for PBXNativeTarget "XGPush" */ = {
289 | isa = XCConfigurationList;
290 | buildConfigurations = (
291 | C50FF02E1D54262A00CEF3D0 /* Debug */,
292 | C50FF02F1D54262A00CEF3D0 /* Release */,
293 | );
294 | defaultConfigurationIsVisible = 0;
295 | defaultConfigurationName = Release;
296 | };
297 | /* End XCConfigurationList section */
298 | };
299 | rootObject = C50FF01C1D54262A00CEF3D0 /* Project object */;
300 | }
301 |
--------------------------------------------------------------------------------
/ios/XGPush.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/XGPush.xcodeproj/project.xcworkspace/xcuserdata/Jeepeng.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PandaQQ/react-native-xinge-push/3b77b89fa834236fde2220f600d388a4f2d35ec8/ios/XGPush.xcodeproj/project.xcworkspace/xcuserdata/Jeepeng.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/ios/XGPush.xcodeproj/xcuserdata/Jeepeng.xcuserdatad/xcschemes/XGPush.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
55 |
56 |
57 |
63 |
64 |
66 |
67 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/ios/XGPush.xcodeproj/xcuserdata/Jeepeng.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | XGPush.xcscheme
8 |
9 | orderHint
10 | 2
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | C50FF0231D54262A00CEF3D0
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ios/XGPush/XGPushManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // XGPushManager.h
3 | // XGPushManager
4 | //
5 | // Created by Jeepeng on 16/8/5.
6 | // Copyright © 2016年 Jeepeng. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | extern NSString *const RCTRemoteNotificationReceived;
12 |
13 | @interface XGPushManager : RCTEventEmitter
14 |
15 | typedef void (^RCTRemoteNotificationCallback)(UIBackgroundFetchResult result);
16 |
17 | #if !TARGET_OS_TV
18 | + (void)didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
19 | + (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
20 | + (void)didReceiveRemoteNotification:(NSDictionary *)notification;
21 | + (void)didReceiveRemoteNotification:(NSDictionary *)notification fetchCompletionHandler:(RCTRemoteNotificationCallback)completionHandler;
22 | + (void)didReceiveRemoteMessage:(NSDictionary *)notification;
23 | + (void)didReceiveRemoteMessage:(NSDictionary *)notification fetchCompletionHandler:(RCTRemoteNotificationCallback)completionHandler;
24 | + (void)didReceiveLocalNotification:(UILocalNotification *)notification;
25 | + (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error;
26 | #endif
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/ios/XGPush/XGPushManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // XGPushManager.m
3 | // 参考了 react-native 官方 PushNotificationIOS 的代码
4 | // Created by Jeepeng on 16/8/5.
5 | // Copyright © 2016年 Jeepeng. All rights reserved.
6 | //
7 |
8 | #import "XGPushManager.h"
9 | #import "XGPush.h"
10 |
11 | #import
12 |
13 | #import
14 | #import
15 | #import
16 | #import
17 |
18 | NSString *const MYRCTRemoteNotificationReceived = @"RemoteNotificationReceived";
19 | NSString *const RCTRemoteMessageReceived = @"RemoteMessageReceived";
20 |
21 | static NSString *const kLocalNotificationReceived = @"LocalNotificationReceived";
22 | static NSString *const kRemoteNotificationsRegistered = @"RemoteNotificationsRegistered";
23 | static NSString *const kRegisterUserNotificationSettings = @"RegisterUserNotificationSettings";
24 | static NSString *const kRemoteNotificationRegistrationFailed = @"RemoteNotificationRegistrationFailed";
25 |
26 | static NSString *const kErrorUnableToRequestPermissions = @"E_UNABLE_TO_REQUEST_PERMISSIONS";
27 |
28 | #if !TARGET_OS_TV
29 | @implementation RCTConvert (NSCalendarUnit)
30 |
31 | RCT_ENUM_CONVERTER(NSCalendarUnit,
32 | (@{
33 | @"year": @(NSCalendarUnitYear),
34 | @"month": @(NSCalendarUnitMonth),
35 | @"week": @(NSCalendarUnitWeekOfYear),
36 | @"day": @(NSCalendarUnitDay),
37 | @"hour": @(NSCalendarUnitHour),
38 | @"minute": @(NSCalendarUnitMinute)
39 | }),
40 | 0,
41 | integerValue)
42 |
43 | @end
44 |
45 | @interface XGPushManager ()
46 | @property (nonatomic, strong) NSMutableDictionary *remoteNotificationCallbacks;
47 | @end
48 |
49 | @implementation RCTConvert (UILocalNotification)
50 |
51 | + (UILocalNotification *)UILocalNotification:(id)json
52 | {
53 | NSDictionary *details = [self NSDictionary:json];
54 | BOOL isSilent = [RCTConvert BOOL:details[@"isSilent"]];
55 | UILocalNotification *notification = [UILocalNotification new];
56 | notification.alertTitle = [RCTConvert NSString:details[@"alertTitle"]];
57 | notification.fireDate = [RCTConvert NSDate:details[@"fireDate"]] ?: [NSDate date];
58 | notification.alertBody = [RCTConvert NSString:details[@"alertBody"]];
59 | notification.alertAction = [RCTConvert NSString:details[@"alertAction"]];
60 | notification.userInfo = [RCTConvert NSDictionary:details[@"userInfo"]];
61 | notification.category = [RCTConvert NSString:details[@"category"]];
62 | notification.repeatInterval = [RCTConvert NSCalendarUnit:details[@"repeatInterval"]];
63 | if (details[@"applicationIconBadgeNumber"]) {
64 | notification.applicationIconBadgeNumber = [RCTConvert NSInteger:details[@"applicationIconBadgeNumber"]];
65 | }
66 | if (!isSilent) {
67 | notification.soundName = [RCTConvert NSString:details[@"soundName"]] ?: UILocalNotificationDefaultSoundName;
68 | }
69 | return notification;
70 | }
71 |
72 | RCT_ENUM_CONVERTER(UIBackgroundFetchResult, (@{
73 | @"UIBackgroundFetchResultNewData": @(UIBackgroundFetchResultNewData),
74 | @"UIBackgroundFetchResultNoData": @(UIBackgroundFetchResultNoData),
75 | @"UIBackgroundFetchResultFailed": @(UIBackgroundFetchResultFailed),
76 | }), UIBackgroundFetchResultNoData, integerValue)
77 |
78 | @end
79 | #endif //TARGET_OS_TV
80 |
81 | @implementation XGPushManager
82 | {
83 | RCTPromiseResolveBlock _requestPermissionsResolveBlock;
84 | }
85 |
86 | #if !TARGET_OS_TV
87 |
88 | static NSDictionary *RCTFormatLocalNotification(UILocalNotification *notification)
89 | {
90 | NSMutableDictionary *formattedLocalNotification = [NSMutableDictionary dictionary];
91 | if (notification.fireDate) {
92 | NSDateFormatter *formatter = [NSDateFormatter new];
93 | [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"];
94 | NSString *fireDateString = [formatter stringFromDate:notification.fireDate];
95 | formattedLocalNotification[@"fireDate"] = fireDateString;
96 | }
97 | formattedLocalNotification[@"alertAction"] = RCTNullIfNil(notification.alertAction);
98 | formattedLocalNotification[@"alertBody"] = RCTNullIfNil(notification.alertBody);
99 | formattedLocalNotification[@"applicationIconBadgeNumber"] = @(notification.applicationIconBadgeNumber);
100 | formattedLocalNotification[@"category"] = RCTNullIfNil(notification.category);
101 | formattedLocalNotification[@"soundName"] = RCTNullIfNil(notification.soundName);
102 | formattedLocalNotification[@"userInfo"] = RCTNullIfNil(RCTJSONClean(notification.userInfo));
103 | formattedLocalNotification[@"remote"] = @NO;
104 | return formattedLocalNotification;
105 | }
106 |
107 | static NSDictionary *RCTFormatUNNotification(UNNotification *notification)
108 | {
109 | NSMutableDictionary *formattedNotification = [NSMutableDictionary dictionary];
110 | UNNotificationContent *content = notification.request.content;
111 |
112 | formattedNotification[@"identifier"] = notification.request.identifier;
113 |
114 | if (notification.date) {
115 | NSDateFormatter *formatter = [NSDateFormatter new];
116 | [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"];
117 | NSString *dateString = [formatter stringFromDate:notification.date];
118 | formattedNotification[@"date"] = dateString;
119 | }
120 |
121 | formattedNotification[@"title"] = RCTNullIfNil(content.title);
122 | formattedNotification[@"body"] = RCTNullIfNil(content.body);
123 | formattedNotification[@"category"] = RCTNullIfNil(content.categoryIdentifier);
124 | formattedNotification[@"thread-id"] = RCTNullIfNil(content.threadIdentifier);
125 | formattedNotification[@"userInfo"] = RCTNullIfNil(RCTJSONClean(content.userInfo));
126 |
127 | return formattedNotification;
128 | }
129 |
130 | #endif //TARGET_OS_TV
131 |
132 | RCT_EXPORT_MODULE()
133 |
134 | - (dispatch_queue_t)methodQueue
135 | {
136 | return dispatch_get_main_queue();
137 | }
138 |
139 | #if !TARGET_OS_TV
140 | - (void)startObserving
141 | {
142 | [[NSNotificationCenter defaultCenter] addObserver:self
143 | selector:@selector(handleLocalNotificationReceived:)
144 | name:kLocalNotificationReceived
145 | object:nil];
146 |
147 | [[NSNotificationCenter defaultCenter] addObserver:self
148 | selector:@selector(handleRemoteMessageReceived:)
149 | name:RCTRemoteMessageReceived
150 | object:nil];
151 | [[NSNotificationCenter defaultCenter] addObserver:self
152 | selector:@selector(handleRemoteNotificationReceived:)
153 | name:MYRCTRemoteNotificationReceived
154 | object:nil];
155 | [[NSNotificationCenter defaultCenter] addObserver:self
156 | selector:@selector(handleRegisterUserNotificationSettings:)
157 | name:kRegisterUserNotificationSettings
158 | object:nil];
159 | [[NSNotificationCenter defaultCenter] addObserver:self
160 | selector:@selector(handleRemoteNotificationsRegistered:)
161 | name:kRemoteNotificationsRegistered
162 | object:nil];
163 | [[NSNotificationCenter defaultCenter] addObserver:self
164 | selector:@selector(handleRemoteNotificationRegistrationError:)
165 | name:kRemoteNotificationRegistrationFailed
166 | object:nil];
167 | }
168 |
169 | - (void)stopObserving
170 | {
171 | [[NSNotificationCenter defaultCenter] removeObserver:self];
172 | }
173 |
174 | - (NSArray *)supportedEvents
175 | {
176 | return @[@"localNotificationReceived",
177 | @"remoteNotificationReceived",
178 | @"remoteMessageReceived",
179 | @"remoteNotificationsRegistered",
180 | @"remoteNotificationRegistrationError"];
181 | }
182 |
183 | + (void)didRegisterUserNotificationSettings:(__unused UIUserNotificationSettings *)notificationSettings
184 | {
185 | if ([UIApplication instancesRespondToSelector:@selector(registerForRemoteNotifications)]) {
186 | [RCTSharedApplication() registerForRemoteNotifications];
187 | [[NSNotificationCenter defaultCenter] postNotificationName:kRegisterUserNotificationSettings
188 | object:self
189 | userInfo:@{@"notificationSettings": notificationSettings}];
190 | }
191 | }
192 |
193 | + (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
194 | {
195 | NSMutableString *hexString = [NSMutableString string];
196 | NSUInteger deviceTokenLength = deviceToken.length;
197 | const unsigned char *bytes = deviceToken.bytes;
198 | for (NSUInteger i = 0; i < deviceTokenLength; i++) {
199 | [hexString appendFormat:@"%02x", bytes[i]];
200 | }
201 | [[NSNotificationCenter defaultCenter] postNotificationName:kRemoteNotificationsRegistered
202 | object:self
203 | userInfo:@{@"deviceToken" : [hexString copy]}];
204 | }
205 |
206 | + (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
207 | {
208 | [[NSNotificationCenter defaultCenter] postNotificationName:kRemoteNotificationRegistrationFailed
209 | object:self
210 | userInfo:@{@"error": error}];
211 | }
212 |
213 | // iOS 10 新增 API
214 | // iOS 10 会走新 API, iOS 10 以前会走到老 API
215 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
216 | // App 用户点击通知
217 | // App 用户选择通知中的行为
218 | // App 用户在通知中心清除消息
219 | // 无论本地推送还是远程推送都会走这个回调
220 | - (void)xgPushUserNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
221 | UNNotification * notification = response.notification;
222 |
223 | if ([response.actionIdentifier isEqualToString:@"xgaction001"]) {
224 | NSLog(@"click from Action1");
225 | } else if ([response.actionIdentifier isEqualToString:@"xgaction002"]) {
226 | NSLog(@"click from Action2");
227 | }
228 | UIApplicationState state = [RCTSharedApplication() applicationState];
229 | NSLog(@"state = %ld, UIApplicationStateActive = %ld", (long)state, (long)UIApplicationStateActive);
230 |
231 | BOOL isBackground = (state != UIApplicationStateActive);
232 | NSMutableDictionary *remoteNotification = [NSMutableDictionary dictionaryWithDictionary:notification.request.content.userInfo];
233 | remoteNotification[@"clicked"] = @YES;
234 | if(isBackground) {
235 | remoteNotification[@"background"] = @YES;
236 | }
237 | NSLog(@"[XGPush] click notification %@", remoteNotification);
238 | NSDictionary * userInfo = @{@"notification": remoteNotification};
239 | [[NSNotificationCenter defaultCenter] postNotificationName:MYRCTRemoteNotificationReceived
240 | object:self
241 | userInfo:userInfo];
242 | [[XGPush defaultManager] reportXGNotificationResponse:response];
243 |
244 | completionHandler();
245 | }
246 |
247 | // App 在前台弹通知需要调用这个接口
248 | - (void)xgPushUserNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
249 | NSDictionary * userInfo = notification.request.content.userInfo;
250 | NSLog(@"[XGPush] willPresentNotification notification %@", userInfo);
251 | [[XGPush defaultManager] reportXGNotificationInfo:userInfo];
252 | completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert);
253 | }
254 | #endif
255 |
256 | + (void)didReceiveRemoteNotification:(NSDictionary *)notification
257 | {
258 | NSDictionary *userInfo = @{@"notification": notification};
259 | [[NSNotificationCenter defaultCenter] postNotificationName:MYRCTRemoteNotificationReceived
260 | object:self
261 | userInfo:userInfo];
262 | }
263 |
264 | + (void)didReceiveRemoteNotification:(NSDictionary *)notification
265 | fetchCompletionHandler:(RCTRemoteNotificationCallback)completionHandler
266 | {
267 | NSDictionary *userInfo = @{@"notification": notification, @"completionHandler": completionHandler};
268 | NSLog(@"%s, notification is %@", __FUNCTION__, notification);
269 | [[NSNotificationCenter defaultCenter] postNotificationName:MYRCTRemoteNotificationReceived
270 | object:self
271 | userInfo:userInfo];
272 | }
273 |
274 | + (void)didReceiveRemoteMessage:(NSDictionary *)notification
275 | {
276 | NSDictionary *userInfo = @{@"notification": notification};
277 | [[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteMessageReceived
278 | object:self
279 | userInfo:userInfo];
280 | }
281 |
282 | + (void)didReceiveRemoteMessage:(NSDictionary *)notification
283 | fetchCompletionHandler:(RCTRemoteNotificationCallback)completionHandler
284 | {
285 | NSDictionary *userInfo = @{@"notification": notification, @"completionHandler": completionHandler};
286 | NSLog(@"%s, notification is %@", __FUNCTION__, notification);
287 | [[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteMessageReceived
288 | object:self
289 | userInfo:userInfo];
290 | }
291 |
292 | + (void)didReceiveLocalNotification:(UILocalNotification *)notification
293 | {
294 | NSLog(@"%s, notification is %@", __FUNCTION__, notification);
295 | [[NSNotificationCenter defaultCenter] postNotificationName:kLocalNotificationReceived
296 | object:self
297 | userInfo:RCTFormatLocalNotification(notification)];
298 | }
299 |
300 | - (void)handleLocalNotificationReceived:(NSNotification *)notification
301 | {
302 | [self sendEventWithName:@"localNotificationReceived" body:notification.userInfo];
303 | }
304 |
305 | - (void)handleRemoteMessageReceived:(NSNotification *)notification
306 | {
307 | NSMutableDictionary *remoteNotification = [NSMutableDictionary dictionary];
308 | remoteNotification[@"content"] = notification.userInfo[@"notification"];
309 | RCTRemoteNotificationCallback completionHandler = notification.userInfo[@"completionHandler"];
310 | NSString *notificationId = [[NSUUID UUID] UUIDString];
311 | remoteNotification[@"notificationId"] = notificationId;
312 | remoteNotification[@"remote"] = @YES;
313 | if (completionHandler) {
314 | if (!self.remoteNotificationCallbacks) {
315 | // Lazy initialization
316 | self.remoteNotificationCallbacks = [NSMutableDictionary dictionary];
317 | }
318 | self.remoteNotificationCallbacks[notificationId] = completionHandler;
319 | }
320 |
321 | [self sendEventWithName:@"remoteMessageReceived" body:remoteNotification];
322 | }
323 |
324 | - (void)handleRemoteNotificationReceived:(NSNotification *)notification
325 | {
326 | NSMutableDictionary *remoteNotification = [NSMutableDictionary dictionaryWithDictionary:notification.userInfo[@"notification"]];
327 | RCTRemoteNotificationCallback completionHandler = notification.userInfo[@"completionHandler"];
328 | NSString *notificationId = [[NSUUID UUID] UUIDString];
329 | remoteNotification[@"notificationId"] = notificationId;
330 | remoteNotification[@"remote"] = @YES;
331 | if (completionHandler) {
332 | if (!self.remoteNotificationCallbacks) {
333 | // Lazy initialization
334 | self.remoteNotificationCallbacks = [NSMutableDictionary dictionary];
335 | }
336 | self.remoteNotificationCallbacks[notificationId] = completionHandler;
337 | }
338 |
339 | [self sendEventWithName:@"remoteNotificationReceived" body:remoteNotification];
340 | }
341 |
342 | - (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
343 | {
344 | [self sendEventWithName:@"remoteNotificationsRegistered" body:notification.userInfo];
345 | }
346 |
347 | - (void)handleRemoteNotificationRegistrationError:(NSNotification *)notification
348 | {
349 | NSError *error = notification.userInfo[@"error"];
350 | NSDictionary *errorDetails = @{
351 | @"message": error.localizedDescription,
352 | @"code": @(error.code),
353 | @"details": error.userInfo,
354 | };
355 | NSLog(@"%s, notification is %@", __FUNCTION__, notification);
356 | [self sendEventWithName:@"remoteNotificationRegistrationError" body:errorDetails];
357 | }
358 |
359 | - (void)handleRegisterUserNotificationSettings:(NSNotification *)notification
360 | {
361 | if (_requestPermissionsResolveBlock == nil) {
362 | return;
363 | }
364 |
365 | UIUserNotificationSettings *notificationSettings = notification.userInfo[@"notificationSettings"];
366 | NSDictionary *notificationTypes = @{
367 | @"alert": @((notificationSettings.types & UIUserNotificationTypeAlert) > 0),
368 | @"sound": @((notificationSettings.types & UIUserNotificationTypeSound) > 0),
369 | @"badge": @((notificationSettings.types & UIUserNotificationTypeBadge) > 0),
370 | };
371 |
372 | _requestPermissionsResolveBlock(notificationTypes);
373 | // Clean up listener added in requestPermissions
374 | [self removeListeners:1];
375 | _requestPermissionsResolveBlock = nil;
376 | }
377 |
378 | RCT_EXPORT_METHOD(onFinishRemoteNotification:(NSString *)notificationId fetchResult:(UIBackgroundFetchResult)result) {
379 | RCTRemoteNotificationCallback completionHandler = self.remoteNotificationCallbacks[notificationId];
380 | if (!completionHandler) {
381 | RCTLogError(@"There is no completion handler with notification id: %@", notificationId);
382 | return;
383 | }
384 | completionHandler(result);
385 | [self.remoteNotificationCallbacks removeObjectForKey:notificationId];
386 | }
387 |
388 | /**
389 | * Update the application icon badge number on the home screen
390 | */
391 | RCT_EXPORT_METHOD(setApplicationIconBadgeNumber:(NSInteger)number)
392 | {
393 | RCTSharedApplication().applicationIconBadgeNumber = number;
394 | }
395 |
396 | /**
397 | * Get the current application icon badge number on the home screen
398 | */
399 | RCT_EXPORT_METHOD(getApplicationIconBadgeNumber:(RCTResponseSenderBlock)callback)
400 | {
401 | callback(@[@(RCTSharedApplication().applicationIconBadgeNumber)]);
402 | }
403 |
404 | RCT_EXPORT_METHOD(requestPermissions:(NSDictionary *)permissions
405 | resolver:(RCTPromiseResolveBlock)resolve
406 | rejecter:(RCTPromiseRejectBlock)reject)
407 | {
408 | if (RCTRunningInAppExtension()) {
409 | reject(kErrorUnableToRequestPermissions, nil, RCTErrorWithMessage(@"Requesting push notifications is currently unavailable in an app extension"));
410 | return;
411 | }
412 |
413 | if (_requestPermissionsResolveBlock != nil) {
414 | RCTLogError(@"Cannot call requestPermissions twice before the first has returned.");
415 | return;
416 | }
417 |
418 | // Add a listener to make sure that startObserving has been called
419 | [self addListener:@"remoteNotificationsRegistered"];
420 | _requestPermissionsResolveBlock = resolve;
421 |
422 | UIUserNotificationType types = UIUserNotificationTypeNone;
423 | if (permissions) {
424 | if ([RCTConvert BOOL:permissions[@"alert"]]) {
425 | types |= UIUserNotificationTypeAlert;
426 | }
427 | if ([RCTConvert BOOL:permissions[@"badge"]]) {
428 | types |= UIUserNotificationTypeBadge;
429 | }
430 | if ([RCTConvert BOOL:permissions[@"sound"]]) {
431 | types |= UIUserNotificationTypeSound;
432 | }
433 | } else {
434 | types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
435 | }
436 |
437 | UIUserNotificationSettings *notificationSettings =
438 | [UIUserNotificationSettings settingsForTypes:types categories:nil];
439 | [RCTSharedApplication() registerUserNotificationSettings:notificationSettings];
440 | }
441 |
442 | RCT_EXPORT_METHOD(abandonPermissions)
443 | {
444 | [RCTSharedApplication() unregisterForRemoteNotifications];
445 | }
446 |
447 | RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback)
448 | {
449 | if (RCTRunningInAppExtension()) {
450 | callback(@[@{@"alert": @NO, @"badge": @NO, @"sound": @NO}]);
451 | return;
452 | }
453 |
454 | NSUInteger types = [RCTSharedApplication() currentUserNotificationSettings].types;
455 | callback(@[@{
456 | @"alert": @((types & UIUserNotificationTypeAlert) > 0),
457 | @"badge": @((types & UIUserNotificationTypeBadge) > 0),
458 | @"sound": @((types & UIUserNotificationTypeSound) > 0),
459 | }]);
460 | }
461 |
462 | RCT_EXPORT_METHOD(presentLocalNotification:(UILocalNotification *)notification)
463 | {
464 | [RCTSharedApplication() presentLocalNotificationNow:notification];
465 | }
466 |
467 | RCT_EXPORT_METHOD(scheduleLocalNotification:(UILocalNotification *)notification)
468 | {
469 | [RCTSharedApplication() scheduleLocalNotification:notification];
470 | }
471 |
472 | RCT_EXPORT_METHOD(cancelAllLocalNotifications)
473 | {
474 | [RCTSharedApplication() cancelAllLocalNotifications];
475 | }
476 |
477 | RCT_EXPORT_METHOD(cancelLocalNotifications:(NSDictionary *)userInfo)
478 | {
479 | for (UILocalNotification *notification in RCTSharedApplication().scheduledLocalNotifications) {
480 | __block BOOL matchesAll = YES;
481 | NSDictionary *notificationInfo = notification.userInfo;
482 | // Note: we do this with a loop instead of just `isEqualToDictionary:`
483 | // because we only require that all specified userInfo values match the
484 | // notificationInfo values - notificationInfo may contain additional values
485 | // which we don't care about.
486 | [userInfo enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
487 | if (![notificationInfo[key] isEqual:obj]) {
488 | matchesAll = NO;
489 | *stop = YES;
490 | }
491 | }];
492 | if (matchesAll) {
493 | [RCTSharedApplication() cancelLocalNotification:notification];
494 | }
495 | }
496 | }
497 |
498 | RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve
499 | reject:(__unused RCTPromiseRejectBlock)reject)
500 | {
501 | NSMutableDictionary *initialNotification =
502 | [self.bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] mutableCopy];
503 |
504 | UILocalNotification *initialLocalNotification =
505 | self.bridge.launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
506 |
507 | // Remove all delivered notifications after get initial notifications
508 | if ([UNUserNotificationCenter class]) {
509 | UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
510 | [center removeAllDeliveredNotifications];
511 | }
512 |
513 | if (initialNotification) {
514 | initialNotification[@"remote"] = @YES;
515 | resolve(initialNotification);
516 | } else if (initialLocalNotification) {
517 | resolve(RCTFormatLocalNotification(initialLocalNotification));
518 | } else {
519 | resolve((id)kCFNull);
520 | }
521 | }
522 |
523 | RCT_EXPORT_METHOD(getScheduledLocalNotifications:(RCTResponseSenderBlock)callback)
524 | {
525 | NSArray *scheduledLocalNotifications = RCTSharedApplication().scheduledLocalNotifications;
526 | NSMutableArray *formattedScheduledLocalNotifications = [NSMutableArray new];
527 | for (UILocalNotification *notification in scheduledLocalNotifications) {
528 | [formattedScheduledLocalNotifications addObject:RCTFormatLocalNotification(notification)];
529 | }
530 | callback(@[formattedScheduledLocalNotifications]);
531 | }
532 |
533 | RCT_EXPORT_METHOD(removeAllDeliveredNotifications)
534 | {
535 | if ([UNUserNotificationCenter class]) {
536 | UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
537 | [center removeAllDeliveredNotifications];
538 | }
539 | }
540 |
541 | RCT_EXPORT_METHOD(removeDeliveredNotifications:(NSArray *)identifiers)
542 | {
543 | if ([UNUserNotificationCenter class]) {
544 | UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
545 | [center removeDeliveredNotificationsWithIdentifiers:identifiers];
546 | }
547 | }
548 |
549 | RCT_EXPORT_METHOD(getDeliveredNotifications:(RCTResponseSenderBlock)callback)
550 | {
551 | if ([UNUserNotificationCenter class]) {
552 | UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
553 | [center getDeliveredNotificationsWithCompletionHandler:^(NSArray *_Nonnull notifications) {
554 | NSMutableArray *formattedNotifications = [NSMutableArray new];
555 |
556 | for (UNNotification *notification in notifications) {
557 | [formattedNotifications addObject:RCTFormatUNNotification(notification)];
558 | }
559 | callback(@[formattedNotifications]);
560 | }];
561 | }
562 | }
563 |
564 | /********************* 信鸽 *********************/
565 |
566 | #pragma mark - XGPushDelegate
567 | - (void)xgPushDidFinishStart:(BOOL)isSuccess error:(NSError *)error {
568 | NSLog(@"%s, 启动信鸽服务 %@, error %@", __FUNCTION__, isSuccess?@"成功":@"失败", error);
569 | }
570 |
571 | - (void)xgPushDidFinishStop:(BOOL)isSuccess error:(NSError *)error {
572 | NSLog(@"%s, 注销信鸽服务 %@, error %@", __FUNCTION__, isSuccess?@"成功":@"失败", error);
573 | }
574 |
575 | #pragma mark - XGPushTokenManagerDelegate
576 | - (void)xgPushDidBindWithIdentifier:(NSString *)identifier type:(XGPushTokenBindType)type error:(NSError *)error {
577 | NSLog(@"%s, id is %@, error %@", __FUNCTION__, identifier, error);
578 | }
579 |
580 | - (void)xgPushDidUnbindWithIdentifier:(NSString *)identifier type:(XGPushTokenBindType)type error:(NSError *)error {
581 | NSLog(@"%s, id is %@, error %@", __FUNCTION__, identifier, error);
582 | }
583 |
584 | /**
585 | * 打开 Debug 模式以后可以在终端看到详细的信鸽 Debug 信息.方便定位问题
586 | */
587 | RCT_EXPORT_METHOD(setEnableDebug:(BOOL)enableDebug)
588 | {
589 | [[XGPush defaultManager] setEnableDebug:enableDebug];
590 | }
591 |
592 | /**
593 | * 查看debug开关是否打开
594 | */
595 | RCT_EXPORT_METHOD(isEnableDebug:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
596 | {
597 | BOOL debugEnabled = [[XGPush defaultManager] isEnableDebug];
598 | resolve(@(debugEnabled));
599 | }
600 |
601 | /**
602 | @brief 通过使用在信鸽官网注册的应用的信息,启动信鸽推送服务
603 |
604 | @param appID 通过前台申请的应用ID
605 | @param appKey 通过前台申请的appKey
606 | @param delegate 回调对象
607 | @note 接口所需参数必须要正确填写,反之信鸽服务将不能正确为应用推送消息
608 | */
609 | RCT_EXPORT_METHOD(startXGWithAppID:(uint64_t)appID appKey:(nonnull NSString *)appKey)
610 | {
611 | [[XGPush defaultManager] startXGWithAppID:appID appKey:appKey delegate:self];
612 | }
613 |
614 | /**
615 | @brief 停止信鸽推送服务
616 | @note 调用此方法将导致当前设备不再接受信鸽服务推送的消息.如果再次需要接收信鸽服务的消息推送,则必须需要再次调用startXG:withAppKey:delegate:方法重启信鸽推送服务
617 | */
618 | RCT_EXPORT_METHOD(stopXGNotification)
619 | {
620 | [[XGPush defaultManager] stopXGNotification];
621 | }
622 |
623 | /**
624 | @brief 上报地理位置信息
625 |
626 | @param latitude 纬度
627 | @param longitude 经度
628 | */
629 | RCT_EXPORT_METHOD(reportLocationWithLatitude:(double)latitude longitude:(double)longitude) {
630 | [[XGPush defaultManager] reportLocationWithLatitude: latitude longitude: longitude];
631 | }
632 |
633 | /**
634 | @brief 上报当前App角标数到信鸽服务器
635 |
636 | @param badgeNumber 应用的角标数
637 | @note (后台维护中)此接口是为了实现角标+1的功能,服务器会在这个数值基础上进行角标数新增的操作,调用成功之后,会覆盖之前值。
638 | */
639 | RCT_EXPORT_METHOD(setBadge:(NSInteger)badgeNumber) {
640 | [[XGPush defaultManager] setBadge: badgeNumber];
641 | }
642 |
643 | /**
644 | @brief 查询设备通知权限是否被用户允许
645 |
646 | @param handler 查询结果的返回方法
647 | @note iOS 10 or later 回调是异步地执行
648 | */
649 | RCT_EXPORT_METHOD(deviceNotificationIsAllowed:(nonnull void (^)(BOOL isAllowed))handler) {
650 |
651 | }
652 |
653 | /**
654 | * 绑定标签,一个设备可以绑定多个标签(多次调用)
655 | */
656 | RCT_EXPORT_METHOD(bindWithTag:tag)
657 | {
658 | [[XGPushTokenManager defaultTokenManager] bindWithIdentifier:tag type:XGPushTokenBindTypeTag];
659 | }
660 |
661 | /**
662 | 绑定账号
663 | */
664 | RCT_EXPORT_METHOD(bindWithAccount:account
665 | resolver:(RCTPromiseResolveBlock)resolve
666 | rejecter:(RCTPromiseRejectBlock)reject)
667 | {
668 | [[XGPushTokenManager defaultTokenManager] bindWithIdentifier:account type:XGPushTokenBindTypeAccount];
669 | resolve([[XGPushTokenManager defaultTokenManager] deviceTokenString]);
670 | }
671 |
672 |
673 | /**
674 | 解绑标签
675 | */
676 | RCT_EXPORT_METHOD(unbindWithTag:tag)
677 | {
678 | [[XGPushTokenManager defaultTokenManager] unbindWithIdentifer:tag type:XGPushTokenBindTypeTag];
679 | }
680 |
681 | /**
682 | 解绑账号
683 | */
684 | RCT_EXPORT_METHOD(unbindWithAccount:account)
685 | {
686 | [[XGPushTokenManager defaultTokenManager] unbindWithIdentifer:account type:XGPushTokenBindTypeAccount];
687 | }
688 |
689 | /**
690 | 获取版本号
691 | */
692 | RCT_EXPORT_METHOD(sdkVersion:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
693 | {
694 | NSString* version = [[XGPush defaultManager] sdkVersion];
695 | resolve(version);
696 | }
697 |
698 | #else //TARGET_OS_TV
699 |
700 | - (NSArray *)supportedEvents
701 | {
702 | return @[];
703 | }
704 |
705 | #endif //TARGET_OS_TV
706 |
707 | @end
708 |
--------------------------------------------------------------------------------
/ios/libXG-SDK.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PandaQQ/react-native-xinge-push/3b77b89fa834236fde2220f600d388a4f2d35ec8/ios/libXG-SDK.a
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-xinge-push",
3 | "version": "0.8.0",
4 | "description": "Xinge push for react-native",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/wanxsb/react-native-xinge-push.git"
12 | },
13 | "keywords": [
14 | "xinge",
15 | "xinge-push",
16 | "xgpush",
17 | "react-native"
18 | ],
19 | "author": "Jeepeng",
20 | "license": "Apache-2.0",
21 | "bugs": {
22 | "url": "https://github.com/wanxsb/react-native-xinge-push/issues"
23 | },
24 | "homepage": "https://github.com/wanxsb/react-native-xinge-push#readme"
25 | }
26 |
--------------------------------------------------------------------------------
/react-native-xinge-push.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod spec lint react-native-xinge-push.podspec' to ensure this is a
3 | # valid spec and to remove all comments including this before submitting the spec.
4 | #
5 | # To learn more about Podspec attributes see https://guides.cocoapods.org/syntax/podspec.html
6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
7 | #
8 |
9 | require 'json'
10 |
11 | package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
12 |
13 | Pod::Spec.new do |s|
14 |
15 | s.name = 'react-native-xinge-push'
16 | s.version = package['version']
17 | s.summary = package['description']
18 | s.license = package['license']
19 |
20 | s.authors = package['author']
21 | s.homepage = package['homepage']
22 | s.platform = :ios, "9.0"
23 |
24 | s.source = { :git => "https://github.com/PandaQQ/react-native-xinge-push.git", :tag => "v#{s.version}" }
25 | s.source_files = "ios/**/*.{h,m}"
26 |
27 | s.dependency 'React'
28 | s.vendored_libraries = "ios/libXG-SDK.a"
29 | s.requires_arc = true
30 | s.frameworks = 'SystemConfiguration','CoreTelephony', 'UserNotifications'
31 | s.library = 'sqlite3','c++','z'
32 | # spec.public_header_files = "Classes/**/*.h"
33 |
34 |
35 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
36 | #
37 | # A list of resources included with the Pod. These are copied into the
38 | # target bundle with a build phase script. Anything else will be cleaned.
39 | # You can preserve files from being cleaned, please don't preserve
40 | # non-essential files like tests, examples and documentation.
41 | #
42 |
43 | # spec.resource = "icon.png"
44 | # spec.resources = "Resources/*.png"
45 |
46 | # spec.preserve_paths = "FilesToSave", "MoreFilesToSave"
47 |
48 |
49 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
50 | #
51 | # Link your library with frameworks, or libraries. Libraries do not include
52 | # the lib prefix of their name.
53 | #
54 |
55 | # spec.framework = "SomeFramework"
56 | # spec.frameworks = "SomeFramework", "AnotherFramework"
57 |
58 | # spec.library = "iconv"
59 | # spec.libraries = "iconv", "xml2"
60 |
61 |
62 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
63 | #
64 | # If your library depends on compiler flags you can set them in the xcconfig hash
65 | # where they will only apply to your library. If you depend on other Podspecs
66 | # you can include multiple dependencies to ensure it works.
67 |
68 | # spec.requires_arc = true
69 |
70 | # spec.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
71 | # spec.dependency "JSONKit", "~> 1.4"
72 |
73 | end
74 |
--------------------------------------------------------------------------------