├── Example
├── App.config
├── Properties
│ └── AssemblyInfo.cs
├── Example.sln
├── Example.csproj
└── Example.cs
├── Jiguang.JPush
├── Model
│ ├── HttpResponse.cs
│ ├── CallBack.cs
│ ├── BatchPushPayload.cs
│ ├── Message.cs
│ ├── DevicePayload.cs
│ ├── SmsMessage.cs
│ ├── Notification3rd.cs
│ ├── SinglePayload.cs
│ ├── Audience.cs
│ ├── PushPayload.cs
│ ├── Trigger.cs
│ ├── Options.cs
│ └── Notification.cs
├── Jiguang.JPush.csproj
├── Jiguang.JPush.sln
├── ReportClient.cs
├── JPushClient.cs
├── DeviceClient.cs
└── ScheduleClient.cs
├── .github
└── workflows
│ └── dotnet-desktop.yml
├── license
├── README.md
└── .gitignore
/Example/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Jiguang.JPush/Model/HttpResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Net.Http.Headers;
3 |
4 | namespace Jiguang.JPush.Model
5 | {
6 | public class HttpResponse
7 | {
8 | public HttpStatusCode StatusCode { get; set; }
9 | public HttpResponseHeaders Headers { get; set; }
10 | public string Content { get; set; }
11 |
12 | public HttpResponse(HttpStatusCode statusCode, HttpResponseHeaders headers, string content)
13 | {
14 | StatusCode = statusCode;
15 | Headers = headers;
16 | Content = content;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Jiguang.JPush/Model/CallBack.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Collections.Generic;
3 |
4 | namespace Jiguang.JPush.Model
5 | {
6 | ///
7 | ///
8 | ///
9 | public class CallBack
10 | {
11 | [JsonProperty("url", NullValueHandling = NullValueHandling.Ignore)]
12 | public string Url { get; set; }
13 |
14 | [JsonProperty("params", NullValueHandling = NullValueHandling.Ignore)]
15 | public Dictionary Params { get; set; }
16 |
17 | [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)]
18 | public int Type { get; set; }
19 | }
20 | }
--------------------------------------------------------------------------------
/Jiguang.JPush/Model/BatchPushPayload.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Collections.Generic;
3 |
4 | namespace Jiguang.JPush.Model
5 | {
6 | public class BatchPushPayload
7 | {
8 | [JsonProperty("pushlist")]
9 | public Dictionary Pushlist { get; set; }
10 |
11 | internal string GetJson()
12 | {
13 | return JsonConvert.SerializeObject(this, new JsonSerializerSettings
14 | {
15 | NullValueHandling = NullValueHandling.Ignore,
16 | DefaultValueHandling = DefaultValueHandling.Ignore
17 | });
18 | }
19 |
20 | public override string ToString()
21 | {
22 | return GetJson();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Jiguang.JPush/Model/Message.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Collections;
3 |
4 | namespace Jiguang.JPush.Model
5 | {
6 | ///
7 | /// 自定义消息。
8 | ///
9 | ///
10 | public class Message
11 | {
12 | ///
13 | /// 消息内容本身(必填)。
14 | ///
15 | [JsonProperty("msg_content")]
16 | public string Content { get; set; }
17 |
18 | [JsonProperty("title")]
19 | public string Title { get; set; }
20 |
21 | [JsonProperty("content_type")]
22 | public string ContentType { get; set; }
23 |
24 | [JsonProperty("extras")]
25 | public IDictionary Extras { get; set; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet-desktop.yml:
--------------------------------------------------------------------------------
1 | name: .NET Core
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: windows-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Setup .NET Core
17 | uses: actions/setup-dotnet@v1
18 | with:
19 | dotnet-version: 3.1.415
20 | - name: Install dependencies
21 | run: cd Jiguang.JPush && dotnet restore
22 | - name: Build
23 | run: cd Jiguang.JPush && dotnet build --configuration Release
24 | - name: Test
25 | run: cd Jiguang.JPush && dotnet test --no-restore --verbosity normal
26 | - name: Publish
27 | uses: brandedoutcast/publish-nuget@v2.5.2
28 | with:
29 | PROJECT_FILE_PATH: Jiguang.JPush/Jiguang.JPush.csproj
30 | NUGET_KEY: ${{secrets.NUGET_API_KEY}}
31 |
--------------------------------------------------------------------------------
/Jiguang.JPush/Model/DevicePayload.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Collections.Generic;
3 |
4 | namespace Jiguang.JPush.Model
5 | {
6 | public class DevicePayload
7 | {
8 | [JsonProperty("alias")]
9 | public string Alias { get; set; }
10 |
11 | [JsonProperty("mobile")]
12 | public string Mobile { get; set; }
13 |
14 | [JsonProperty("tags")]
15 | public Dictionary Tags { get; set;}
16 |
17 | private string GetJson()
18 | {
19 | return JsonConvert.SerializeObject(this, new JsonSerializerSettings
20 | {
21 | NullValueHandling = NullValueHandling.Ignore,
22 | DefaultValueHandling = DefaultValueHandling.Ignore
23 | });
24 | }
25 |
26 | public override string ToString()
27 | {
28 | return GetJson();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Jiguang.JPush/Model/SmsMessage.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json;
3 |
4 | namespace Jiguang.JPush.Model
5 | {
6 | ///
7 | /// 短信补充。
8 | ///
9 | ///
10 | public class SmsMessage
11 | {
12 | [JsonProperty("delay_time", DefaultValueHandling = DefaultValueHandling.Include)]
13 | public int DelayTime { get; set; }
14 |
15 | [JsonProperty("signid", NullValueHandling = NullValueHandling.Ignore)]
16 | public int Signid { get; set; }
17 |
18 | [JsonProperty("temp_id", DefaultValueHandling = DefaultValueHandling.Include)]
19 | public long TempId { get; set; }
20 |
21 | [JsonProperty("temp_para", NullValueHandling = NullValueHandling.Ignore)]
22 | public Dictionary TempPara { get; set; }
23 |
24 | [JsonProperty("active_filter", NullValueHandling = NullValueHandling.Ignore)]
25 | public bool? ActiveFilter { get; set; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Example/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("Example")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Example")]
13 | [assembly: AssemblyCopyright("Copyright © 2024")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 会使此程序集中的类型
18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("462b1f04-cb30-4e04-9e3d-5158e6edf128")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
33 | // 方法是按如下所示使用“*”: :
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) JiGuang (jiguang.cn)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Jiguang.JPush/Jiguang.JPush.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard1.1;net45
5 | $(LibraryFrameworks)
6 | True
7 | False
8 | The CSharp api client by Jiguang.
9 | hevin, Jiguang
10 | cn.jiguang
11 | JPush
12 | MIT
13 |
14 | https://github.com/jpush/jpush-api-csharp-client
15 | 1.2.5
16 |
17 |
18 |
19 | bin\Debug\netstandard1.1\Jiguang.JPush.xml
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JPush Library for .NET
2 |
3 | [](https://preview.nuget.org/packages/Jiguang.JPush/)
4 |
5 | 由[极光](https://www.jiguang.cn/)官方支持的 JPush .NET API Client。
6 |
7 | > 注意:**Jiguang.JPush** 为基于 .NET Standard 的重构版本,API 用法有较大改变,不兼容旧版本(**cn.jpush.api**),升级前请注意。
8 |
9 | 项目中的 Example 为 .NET Core 控制台应用。将ExampleConfig.cs.example重命名为ExampleConfig.cs并且填上自己的AppKey、MasterSecret后即可进行单元测试。
10 |
11 | 开发工具:Visual Studio 2017。
12 |
13 | ## Install
14 |
15 | - [NuGet](https://preview.nuget.org/packages/Jiguang.JPush/)
16 |
17 | ## Documents
18 |
19 | [REST API documents](https://docs.jiguang.cn/jpush/server/push/server_overview/).
20 |
21 | ## Support
22 |
23 | [极光社区](https://community.jiguang.cn/)
24 |
25 | ## FAQ
26 |
27 | 1. 如果调用异步方法时出现死锁,即一直没有返回 [HttpResponse](https://github.com/jpush/jsms-api-csharp-client/blob/v2-dev/Jiguang.JSMS/Model/HttpResponse.cs),可参考这篇[文章](https://blogs.msdn.microsoft.com/jpsanders/2017/08/28/asp-net-do-not-use-task-result-in-main-context/)。
28 |
29 | 1. 如果使用的是 .NET Framework 4.0,则需要使用 [v1](https://github.com/jpush/jpush-api-csharp-client/tree/v1) 版本。
30 |
31 | ## Contribute
32 |
33 | Please contribute! [Look at the issues](https://github.com/jpush/jpush-api-csharp-client/issues).
34 |
35 | ## License
36 |
37 | MIT © [JiGuang](https://github.com/jpush/jpush-api-csharp-client/blob/master/license)
38 |
39 | ## Extensions
40 |
41 | .Net core 2.0 可以使用[Jiguang.JPush.Extensions](https://github.com/Weidaicheng/jpush-api-csharp-client.Extensions)扩展添加注入,方便使用。
42 |
--------------------------------------------------------------------------------
/Jiguang.JPush/Model/Notification3rd.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Collections.Generic;
3 |
4 | namespace Jiguang.JPush.Model
5 | {
6 | ///
7 | ///
8 | ///
9 | public class Notification3rd
10 | {
11 | [JsonProperty("title", NullValueHandling = NullValueHandling.Ignore)]
12 | public string Url { get; set; }
13 |
14 | ///
15 | /// 必填。
16 | ///
17 | [JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)]
18 | public string Content { get; set; }
19 |
20 | [JsonProperty("channel_id", NullValueHandling = NullValueHandling.Ignore)]
21 | public string ChannelId { get; set; }
22 |
23 | [JsonProperty("uri_activity", NullValueHandling = NullValueHandling.Ignore)]
24 | public string UriActivity { get; set; }
25 |
26 | [JsonProperty("uri_action", NullValueHandling = NullValueHandling.Ignore)]
27 | public string UriAction { get; set; }
28 |
29 | [JsonProperty("badge_add_num", NullValueHandling = NullValueHandling.Ignore)]
30 | public string BadgeAddNum { get; set; }
31 |
32 | [JsonProperty("badge_class", NullValueHandling = NullValueHandling.Ignore)]
33 | public string BadgeClass { get; set; }
34 |
35 | [JsonProperty("sound", NullValueHandling = NullValueHandling.Ignore)]
36 | public string Sound { get; set; }
37 |
38 | [JsonProperty("extras", NullValueHandling = NullValueHandling.Ignore)]
39 | public Dictionary Extras { get; set; }
40 | }
41 | }
--------------------------------------------------------------------------------
/Example/Example.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.34112.143
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example.csproj", "{462B1F04-CB30-4E04-9E3D-5158E6EDF128}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jiguang.JPush", "..\Jiguang.JPush\Jiguang.JPush.csproj", "{A182F843-FCAC-4497-8006-32541DC772F4}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {462B1F04-CB30-4E04-9E3D-5158E6EDF128}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {462B1F04-CB30-4E04-9E3D-5158E6EDF128}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {462B1F04-CB30-4E04-9E3D-5158E6EDF128}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {462B1F04-CB30-4E04-9E3D-5158E6EDF128}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {A182F843-FCAC-4497-8006-32541DC772F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {A182F843-FCAC-4497-8006-32541DC772F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {A182F843-FCAC-4497-8006-32541DC772F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {A182F843-FCAC-4497-8006-32541DC772F4}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {7E6535B3-8F76-4D64-833B-5A4B8CB18205}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/Jiguang.JPush/Model/SinglePayload.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace Jiguang.JPush.Model
4 | {
5 | public class SinglePayload
6 | {
7 | ///
8 | /// 推送平台。可以为 "android" / "ios" / "all"。
9 | ///
10 | [JsonProperty("platform", DefaultValueHandling = DefaultValueHandling.Include)]
11 | public object Platform { get; set; } = "all";
12 |
13 | ///
14 | /// 推送设备指定。
15 | /// 如果是调用RegID方式批量单推接口(/v3/push/batch/regid/single),那此处就是指定regid值;
16 | /// 如果是调用Alias方式批量单推接口(/v3/push/batch/alias/single),那此处就是指定alias值。
17 | ///
18 | [JsonProperty("target", DefaultValueHandling = DefaultValueHandling.Include)]
19 | public string Target { get; set; }
20 |
21 | [JsonProperty("notification", NullValueHandling = NullValueHandling.Ignore)]
22 | public Notification Notification { get; set; }
23 |
24 | [JsonProperty("message", NullValueHandling = NullValueHandling.Ignore)]
25 | public Message Message { get; set; }
26 |
27 | [JsonProperty("sms_message", NullValueHandling = NullValueHandling.Ignore)]
28 | public SmsMessage SMSMessage { get; set; }
29 |
30 | [JsonProperty("options", DefaultValueHandling = DefaultValueHandling.Include)]
31 | public Options Options { get; set; } = new Options
32 | {
33 | IsApnsProduction = false
34 | };
35 |
36 | internal string GetJson()
37 | {
38 | return JsonConvert.SerializeObject(this, new JsonSerializerSettings
39 | {
40 | NullValueHandling = NullValueHandling.Ignore,
41 | DefaultValueHandling = DefaultValueHandling.Ignore
42 | });
43 | }
44 |
45 | public override string ToString()
46 | {
47 | return GetJson();
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Jiguang.JPush/Jiguang.JPush.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2027
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jiguang.JPush", "Jiguang.JPush.csproj", "{876384B3-898F-4392-8E20-30A1D9E393F0}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {876384B3-898F-4392-8E20-30A1D9E393F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {876384B3-898F-4392-8E20-30A1D9E393F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {876384B3-898F-4392-8E20-30A1D9E393F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {876384B3-898F-4392-8E20-30A1D9E393F0}.Release|Any CPU.Build.0 = Release|Any CPU
18 | {E87821A4-FB7B-4744-8188-17C348ABCE55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {E87821A4-FB7B-4744-8188-17C348ABCE55}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {E87821A4-FB7B-4744-8188-17C348ABCE55}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {E87821A4-FB7B-4744-8188-17C348ABCE55}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {BE150D1B-23E3-4EC3-A6AD-631DAA90D1E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {BE150D1B-23E3-4EC3-A6AD-631DAA90D1E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {BE150D1B-23E3-4EC3-A6AD-631DAA90D1E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {BE150D1B-23E3-4EC3-A6AD-631DAA90D1E5}.Release|Any CPU.Build.0 = Release|Any CPU
26 | EndGlobalSection
27 | GlobalSection(SolutionProperties) = preSolution
28 | HideSolutionNode = FALSE
29 | EndGlobalSection
30 | GlobalSection(ExtensibilityGlobals) = postSolution
31 | SolutionGuid = {D1965B1D-21CA-4A32-8ACC-8B473FC7C659}
32 | EndGlobalSection
33 | EndGlobal
34 |
--------------------------------------------------------------------------------
/Jiguang.JPush/Model/Audience.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json;
3 |
4 | namespace Jiguang.JPush.Model
5 | {
6 | ///
7 | /// 推送目标。
8 | ///
9 | ///
10 | public class Audience
11 | {
12 | ///
13 | /// 多个标签之间取并集(OR)。
14 | /// 每次最多推送 20 个。
15 | ///
16 | [JsonProperty("tag", NullValueHandling = NullValueHandling.Ignore)]
17 | public List Tag { get; set; }
18 |
19 | ///
20 | /// 多个标签之间取交集(AND)。
21 | /// 每次最多推送 20 个。
22 | ///
23 | [JsonProperty("tag_and", NullValueHandling = NullValueHandling.Ignore)]
24 | public List TagAnd { get; set; }
25 |
26 | ///
27 | /// 多个标签之间,先取并集,再对结果取补集。
28 | /// 每次最多推送 20 个。
29 | ///
30 | [JsonProperty("tag_not", NullValueHandling = NullValueHandling.Ignore)]
31 | public List TagNot { get; set; }
32 |
33 | ///
34 | /// 多个别名之间取并集(OR)。
35 | /// 每次最多同时推送 1000 个。
36 | ///
37 | [JsonProperty("alias", NullValueHandling = NullValueHandling.Ignore)]
38 | public List Alias { get; set; }
39 |
40 | ///
41 | /// 多个 registration id 之间取并集(OR)。
42 | /// 每次最多同时推送 1000 个。
43 | ///
44 | [JsonProperty("registration_id", NullValueHandling = NullValueHandling.Ignore)]
45 | public List RegistrationId { get; set; }
46 |
47 | ///
48 | /// 在页面创建的用户分群 ID。
49 | /// 目前一次只能推送一个。
50 | ///
51 | [JsonProperty("segment", NullValueHandling = NullValueHandling.Ignore)]
52 | public List Segment { get; set; }
53 |
54 | ///
55 | /// 在页面创建的 A/B 测试 ID。
56 | /// 目前一次只能推送一个。
57 | ///
58 | [JsonProperty("abtest", NullValueHandling = NullValueHandling.Ignore)]
59 | public List Abtest { get; set; }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Jiguang.JPush/Model/PushPayload.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Converters;
3 |
4 | namespace Jiguang.JPush.Model
5 | {
6 | public class PushPayload
7 | {
8 | [JsonProperty("cid", NullValueHandling = NullValueHandling.Ignore)]
9 | public string CId { get; set; }
10 |
11 | ///
12 | /// 推送平台。可以为 "android" / "ios" / "all"。
13 | ///
14 |
15 | [JsonProperty("callback", NullValueHandling = NullValueHandling.Ignore)]
16 | public CallBack CallBack { get; set; }
17 |
18 | [JsonProperty("notification_3rd", NullValueHandling = NullValueHandling.Ignore)]
19 | public Notification3rd Notification3rd { get; set; }
20 |
21 | [JsonProperty("platform", DefaultValueHandling = DefaultValueHandling.Include)]
22 | public object Platform { get; set; } = "all";
23 |
24 | [JsonProperty("audience", DefaultValueHandling = DefaultValueHandling.Include)]
25 | public object Audience { get; set; } = "all";
26 |
27 | [JsonProperty("notification", NullValueHandling = NullValueHandling.Ignore)]
28 | public Notification Notification { get; set; }
29 |
30 | [JsonProperty("message", NullValueHandling = NullValueHandling.Ignore)]
31 | public Message Message { get; set; }
32 |
33 | [JsonProperty("sms_message", NullValueHandling = NullValueHandling.Ignore)]
34 | public SmsMessage SMSMessage { get; set; }
35 |
36 | [JsonProperty("options", DefaultValueHandling = DefaultValueHandling.Include)]
37 | [JsonConverter(typeof(OptionsJsonConvert))]
38 | public Options Options { get; set; } = new Options
39 | {
40 | IsApnsProduction = false
41 | };
42 |
43 | internal string GetJson()
44 | {
45 | return JsonConvert.SerializeObject(this, new JsonSerializerSettings
46 | {
47 | NullValueHandling = NullValueHandling.Ignore,
48 | DefaultValueHandling = DefaultValueHandling.Ignore
49 | });
50 | }
51 |
52 | public override string ToString()
53 | {
54 | return GetJson();
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Jiguang.JPush/Model/Trigger.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Collections.Generic;
3 |
4 | namespace Jiguang.JPush.Model
5 | {
6 | ///
7 | /// 定期任务触发器。
8 | ///
9 | ///
10 | public class Trigger
11 | {
12 | ///
13 | /// 定期任务开始日期,必须为 24 小时制。
14 | /// 类似:"2017-08-01 12:00:00"
15 | ///
16 | [JsonProperty("start")]
17 | public string StartDate { get; set; }
18 |
19 | ///
20 | /// 定期任务终止日期,必须为 24 小时制。
21 | /// 类似:"2017-12-30 12:00:00"
22 | ///
23 | [JsonProperty("end")]
24 | public string EndDate { get; set; }
25 |
26 | ///
27 | /// 具体的触发时间。
28 | /// 类似:"12:00:00"
29 | ///
30 | [JsonProperty("time")]
31 | public string TriggerTime { get; set; }
32 |
33 | ///
34 | /// 定期任务执行的最小时间单位。
35 | /// 必须为 "day" / "week" / "month" 中的一种。
36 | ///
37 | [JsonProperty("time_unit")]
38 | public string TimeUnit { get; set; }
39 |
40 | ///
41 | /// 定期任务的执行周期(目前最大支持 100)。
42 | /// 比如,当 TimeUnit 为 "day",Frequency 为 2 时,表示每两天触发一次推送。
43 | ///
44 | [JsonProperty("frequency")]
45 | public int Frequency { get; set; }
46 |
47 | ///
48 | /// 当 TimeUnit 为 "week" 或 "month"时,具体的时间表。
49 | /// - 如果 TimeUnit 为 "week": {"mon", "tue", "wed", "thu", "fri", "sat", "sun"};
50 | /// - 如果 TimeUnit 为 "month": {"01", "02"...};
51 | ///
52 | [JsonProperty("point")]
53 | public List TimeList { get; set; }
54 |
55 | private string GetJson()
56 | {
57 | return JsonConvert.SerializeObject(this, new JsonSerializerSettings
58 | {
59 | NullValueHandling = NullValueHandling.Ignore,
60 | DefaultValueHandling = DefaultValueHandling.Ignore
61 | });
62 | }
63 |
64 | public override string ToString()
65 | {
66 | return GetJson();
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Example/Example.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {462B1F04-CB30-4E04-9E3D-5158E6EDF128}
8 | Exe
9 | Example
10 | Example
11 | v4.6.1
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | {a182f843-fcac-4497-8006-32541dc772f4}
55 | Jiguang.JPush
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Jiguang.JPush/Model/Options.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Converters;
3 | using System;
4 | using System.Reflection;
5 | using System.Collections.Generic;
6 |
7 | namespace Jiguang.JPush.Model
8 | {
9 | ///
10 | ///
11 | ///
12 | public class Options
13 | {
14 | ///
15 | /// 推送序号。
16 | /// 用来作为 API 调用标识,API 返回时被原样返回,以方便 API 调用方匹配请求与返回。不能为 0。
17 | ///
18 | [JsonProperty("sendno", NullValueHandling = NullValueHandling.Ignore)]
19 | public int? SendNo { get; set; }
20 |
21 | ///
22 | /// 离线消息保留时长(秒)。
23 | /// 推送当前用户不在线时,为该用户保留多长时间的离线消息,以便其上线时再次推送。默认 86400 (1 天),最长 10 天。设置为 0 表示不保留离线消息,只有推送当前在线的用户可以收到。
24 | ///
25 | [JsonProperty("time_to_live", NullValueHandling = NullValueHandling.Ignore)]
26 | public int? TimeToLive { get; set; }
27 |
28 | ///
29 | /// 要覆盖的消息 ID。
30 | /// 如果当前的推送要覆盖之前的一条推送,这里填写前一条推送的 msg_id 就会产生覆盖效果。覆盖功能起作用的时限是:1 天。
31 | ///
32 | [JsonProperty("override_msg_id", NullValueHandling = NullValueHandling.Ignore)]
33 | public long? OverrideMessageId { get; set; }
34 |
35 | ///
36 | /// iOS 推送是否为生产环境。默认为 false - 开发环境。
37 | /// true: 生产环境;false: 开发环境。
38 | ///
39 | [JsonProperty("apns_production", DefaultValueHandling = DefaultValueHandling.Include)]
40 | public bool IsApnsProduction { get; set; } = false;
41 |
42 | ///
43 | /// 更新 iOS 通知的标识符。
44 | /// APNs 新通知如果匹配到当前通知中心有相同 apns-collapse-id 字段的通知,则会用新通知内容来更新它,并使其置于通知中心首位。collapse id 长度不可超过 64 bytes。
45 | ///
46 | [JsonProperty("apns_collapse_id", NullValueHandling = NullValueHandling.Ignore)]
47 | public string ApnsCollapseId { get; set; }
48 |
49 | ///
50 | /// 定速推送时长(分钟)。
51 | /// 又名缓慢推送。把原本尽可能快的推送速度,降低下来,给定的 n 分钟内,均匀地向这次推送的目标用户推送。最大值为 1400,未设置则不是定速推送。
52 | ///
53 | [JsonProperty("big_push_duration", NullValueHandling = NullValueHandling.Ignore)]
54 | public int? BigPushDuration { get; set; }
55 |
56 | ///
57 | /// 自定义参数
58 | ///
59 | public Dictionary Dict { get; set; }
60 |
61 | public void Add(string key, object value) {
62 | if (Dict == null) {
63 | Dict = new Dictionary();
64 | }
65 | Dict.Add(key, value);
66 | }
67 | }
68 |
69 | public class OptionsJsonConvert : JsonConverter
70 | {
71 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
72 | {
73 | throw new Exception("Unsupport ReadJson convert.");
74 | }
75 |
76 | public override bool CanConvert(Type objectType)
77 | {
78 | if (objectType.FullName == typeof(Options).FullName)
79 | {
80 | return true;
81 | }
82 | else {
83 | return false;
84 | }
85 | }
86 |
87 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
88 | {
89 | if (value == null)
90 | {
91 | writer.WriteNull();
92 | return;
93 | }
94 | writer.WriteStartObject();
95 | Options options = (Options) value;
96 | if (options.SendNo != null) {
97 | writer.WritePropertyName("sendno");
98 | writer.WriteValue(options.SendNo);
99 | }
100 | if (options.TimeToLive != null) {
101 | writer.WritePropertyName("time_to_live");
102 | writer.WriteValue(options.TimeToLive);
103 | }
104 | if (options.OverrideMessageId != null) {
105 | writer.WritePropertyName("override_msg_id");
106 | writer.WriteValue(options.OverrideMessageId);
107 | }
108 | writer.WritePropertyName("apns_production");
109 | writer.WriteValue(options.IsApnsProduction);
110 | if (options.ApnsCollapseId != null) {
111 | writer.WritePropertyName("apns_collapse_id");
112 | writer.WriteValue(options.ApnsCollapseId);
113 | }
114 | if (options.BigPushDuration != null) {
115 | writer.WritePropertyName("big_push_duration");
116 | writer.WriteValue(options.BigPushDuration);
117 | }
118 | if (options.Dict != null) {
119 | foreach (KeyValuePair item in options.Dict)
120 | {
121 | writer.WritePropertyName(item.Key);
122 | serializer.Serialize(writer, item.Value);
123 | }
124 | }
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/Example/Example.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Jiguang.JPush;
3 | using Jiguang.JPush.Model;
4 | using System.Collections.Generic;
5 |
6 |
7 | namespace Example
8 | {
9 | class Example
10 | {
11 | public const string APP_KEY = "Your AppKey";
12 | public const string MASTER_SECRET = "Your MasterSecret";
13 |
14 | private static JPushClient client = new JPushClient(APP_KEY, MASTER_SECRET);
15 |
16 | public static void Main(string[] args)
17 | {
18 | ExecutePushExample();
19 | ExecuteBatchPushExample();
20 | ExecuteDeviceExample();
21 | ExecuteReportExample();
22 | ExecuteReceivedDetailReportExample();
23 | ExecuteMessagesDetialReportExample();
24 | ExecuteScheduleExample();
25 |
26 | Console.ReadLine();
27 | }
28 |
29 | private static void ExecutePushExample()
30 | {
31 | PushPayload pushPayload = new PushPayload()
32 | {
33 | Platform = new List { "android", "ios", "hmos"},
34 | Audience = "all",
35 | Notification = new Notification
36 | {
37 | Alert = "hello jpush",
38 | Android = new Android
39 | {
40 | Alert = "android alert",
41 | Title = "title"
42 | },
43 | IOS = new IOS
44 | {
45 | Alert = "ios alert",
46 | Badge = "+1"
47 | },
48 |
49 | HMOS = new HMOS
50 | {
51 | Alert = "hmos alert",
52 | Title = "title",
53 | Category = "IM",
54 | BadgeAddNum = 1,
55 | ReceiptId = "abc1212"
56 | }
57 | },
58 | Message = new Message
59 | {
60 | Title = "message title",
61 | Content = "message content",
62 | Extras = new Dictionary
63 | {
64 | ["key1"] = "value1"
65 | }
66 | },
67 | Options = new Options
68 | {
69 | IsApnsProduction = true // 设置 iOS 推送生产环境。不设置默认为开发环境。
70 | }
71 | };
72 | var response = client.SendPush(pushPayload);
73 | Console.WriteLine(response.Content);
74 | }
75 |
76 | private static void ExecuteBatchPushExample()
77 | {
78 | SinglePayload singlePayload = new SinglePayload()
79 | {
80 | Platform = new List { "android", "ios", "hmos" },
81 | Target = "flink",
82 | Notification = new Notification
83 | {
84 | Alert = "hello jpush",
85 | Android = new Android
86 | {
87 | Alert = "android alert",
88 | Title = "title"
89 | },
90 | IOS = new IOS
91 | {
92 | Alert = "ios alert",
93 | Badge = "+1"
94 | },
95 | HMOS = new HMOS
96 | {
97 | Alert = "hmos alert",
98 | Title = "title",
99 | Category = "IM",
100 | BadgeAddNum = 1,
101 | ReceiptId = "abc1212",
102 | //Intent = new Dictionary
103 | //{
104 | //["url"] = "scheme://test?key1=val1&key2=val2"
105 | }
106 | // }
107 | },
108 | Message = new Message
109 | {
110 | Title = "message title",
111 | Content = "message content",
112 | Extras = new Dictionary
113 | {
114 | ["key1"] = "value1"
115 | }
116 | },
117 | Options = new Options
118 | {
119 | IsApnsProduction = true // 设置 iOS 推送生产环境。不设置默认为开发环境。
120 | }
121 | };
122 | List singlePayloads = new List();
123 | singlePayloads.Add(singlePayload);
124 | Console.WriteLine("start send");
125 | var response = client.BatchPushByAlias(singlePayloads);
126 | Console.WriteLine(response.Content);
127 | }
128 |
129 | private static void ExecuteDeviceExample()
130 | {
131 | var registrationId = "12145125123151";
132 | var devicePayload = new DevicePayload
133 | {
134 | Alias = "alias1",
135 | Mobile = "12300000000",
136 | Tags = new Dictionary
137 | {
138 | { "add", new List() { "tag1", "tag2" } },
139 | { "remove", new List() { "tag3", "tag4" } }
140 | }
141 | };
142 | var response = client.Device.UpdateDeviceInfo(registrationId, devicePayload);
143 | Console.WriteLine(response.Content);
144 | }
145 |
146 | private static void ExecuteReportExample()
147 | {
148 | var response = client.Report.GetMessageReport(new List { "1251231231" });
149 | Console.WriteLine(response.Content);
150 | }
151 |
152 | private static void ExecuteReceivedDetailReportExample()
153 | {
154 | var response = client.Report.GetReceivedDetailReport(new List { "1251231231" });
155 | Console.WriteLine(response.Content);
156 | }
157 |
158 | private static void ExecuteMessagesDetialReportExample()
159 | {
160 | var response = client.Report.GetMessagesDetailReport(new List { "1251231231" });
161 | Console.WriteLine(response.Content);
162 | }
163 |
164 | private static void ExecuteScheduleExample()
165 | {
166 | var pushPayload = new PushPayload
167 | {
168 | Platform = "all",
169 | Notification = new Notification
170 | {
171 | Alert = "Hello JPush"
172 | }
173 | };
174 | var trigger = new Trigger
175 | {
176 | StartDate = "2017-08-03 12:00:00",
177 | EndDate = "2017-12-30 12:00:00",
178 | TriggerTime = "12:00:00",
179 | TimeUnit = "week",
180 | Frequency = 2,
181 | TimeList = new List
182 | {
183 | "wed", "fri"
184 | }
185 | };
186 | var response = client.Schedule.CreatePeriodicalScheduleTask("task1", pushPayload, trigger);
187 | Console.WriteLine(response.Content);
188 | }
189 | }
190 | }
--------------------------------------------------------------------------------
/Jiguang.JPush/Model/Notification.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Collections.Generic;
3 |
4 | namespace Jiguang.JPush.Model
5 | {
6 | ///
7 | ///
8 | ///
9 | public class Notification
10 | {
11 | [JsonProperty("alert")]
12 | public string Alert { get; set; }
13 |
14 | [JsonProperty("android", NullValueHandling = NullValueHandling.Ignore)]
15 | public Android Android { get; set; }
16 |
17 | [JsonProperty("ios", NullValueHandling = NullValueHandling.Ignore)]
18 | public IOS IOS { get; set; }
19 |
20 | [JsonProperty("hmos", NullValueHandling = NullValueHandling.Ignore)]
21 | public HMOS HMOS { get; set; }
22 | }
23 |
24 | public class Android
25 | {
26 | ///
27 | /// 必填。
28 | ///
29 | [JsonProperty("alert")]
30 | public string Alert { get; set; }
31 |
32 | [JsonProperty("title", NullValueHandling = NullValueHandling.Ignore)]
33 | public string Title { get; set; }
34 |
35 | [JsonProperty("builder_id", NullValueHandling = NullValueHandling.Ignore)]
36 | public int? BuilderId { get; set; }
37 |
38 | [JsonProperty("channel_id", NullValueHandling = NullValueHandling.Ignore)]
39 | public string ChannelId { get; set; }
40 |
41 | [JsonProperty("priority", NullValueHandling = NullValueHandling.Ignore)]
42 | public int? Priority { get; set; }
43 |
44 | [JsonProperty("category", NullValueHandling = NullValueHandling.Ignore)]
45 | public string Category { get; set; }
46 |
47 | [JsonProperty("style", NullValueHandling = NullValueHandling.Ignore)]
48 | public int? Style { get; set; }
49 |
50 | [JsonProperty("alert_type", NullValueHandling = NullValueHandling.Ignore)]
51 | public int? AlertType { get; set; }
52 |
53 | [JsonProperty("big_text", NullValueHandling = NullValueHandling.Ignore)]
54 | public string BigText { get; set; }
55 |
56 | [JsonProperty("inbox", NullValueHandling = NullValueHandling.Ignore)]
57 | public Dictionary Inbox { get; set; }
58 |
59 | [JsonProperty("big_pic_path", NullValueHandling = NullValueHandling.Ignore)]
60 | public string BigPicturePath { get; set; }
61 |
62 | [JsonProperty("large_icon", NullValueHandling = NullValueHandling.Ignore)]
63 | public string LargeIcon { get; set; }
64 |
65 | [JsonProperty("intent", NullValueHandling = NullValueHandling.Ignore)]
66 | public Dictionary Indent { get; set; }
67 |
68 | [JsonProperty("extras", NullValueHandling = NullValueHandling.Ignore)]
69 | public Dictionary Extras { get; set; }
70 |
71 | ///
72 | /// (VIP only)指定开发者想要打开的 Activity,值为 节点的 "android:name" 属性值。
73 | ///
74 | [JsonProperty("uri_activity", NullValueHandling = NullValueHandling.Ignore)]
75 | public string URIActivity { get; set; }
76 |
77 | ///
78 | /// (VIP only)指定打开 Activity 的方式,值为 Intent.java 中预定义的 "access flags" 的取值范围。
79 | ///
80 | [JsonProperty("uri_flag", NullValueHandling = NullValueHandling.Ignore)]
81 | public string URIFlag { get; set; }
82 |
83 | ///
84 | /// (VIP only)指定开发者想要打开的 Activity,值为 -> -> 节点中的 "android:name" 属性值。
85 | ///
86 | [JsonProperty("uri_action", NullValueHandling = NullValueHandling.Ignore)]
87 | public string URIAction { get; set; }
88 | }
89 |
90 | public class IOS
91 | {
92 | ///
93 | /// 可以是 string,也可以是 Apple 官方定义的 alert payload 结构。
94 | ///
95 | ///
96 | [JsonProperty("alert")]
97 | public object Alert { get; set; }
98 |
99 | [JsonProperty("sound", NullValueHandling = NullValueHandling.Ignore)]
100 | public string Sound { get; set; }
101 |
102 | ///
103 | /// 默认角标 +1。
104 | ///
105 | [JsonProperty("badge")]
106 | public string Badge { get; set; } = "+1";
107 |
108 | [JsonProperty("content-available", NullValueHandling = NullValueHandling.Ignore)]
109 | public bool? ContentAvailable { get; set; }
110 |
111 | [JsonProperty("mutable-content", NullValueHandling = NullValueHandling.Ignore)]
112 | public bool? MutableContent { get; set; }
113 |
114 | [JsonProperty("category", NullValueHandling = NullValueHandling.Ignore)]
115 | public string Category { get; set; }
116 |
117 | [JsonProperty("extras", NullValueHandling = NullValueHandling.Ignore)]
118 | public Dictionary Extras { get; set; }
119 |
120 | [JsonProperty("thread-id", NullValueHandling = NullValueHandling.Ignore)]
121 | public string ThreadId { get; set; }
122 | }
123 |
124 | public class HMOS
125 | {
126 | ///
127 | /// 必填。
128 | ///
129 | [JsonProperty("alert")]
130 | public string Alert { get; set; }
131 |
132 | [JsonProperty("title", NullValueHandling = NullValueHandling.Ignore)]
133 | public string Title { get; set; }
134 |
135 | [JsonProperty("category")]
136 | public string Category { get; set; }
137 |
138 | [JsonProperty("large_icon", NullValueHandling = NullValueHandling.Ignore)]
139 | public string LargeIcon { get; set; }
140 |
141 | [JsonProperty("intent", NullValueHandling = NullValueHandling.Ignore)]
142 | public Dictionary Intent { get; set; }
143 |
144 | [JsonProperty("badge_add_num", NullValueHandling = NullValueHandling.Ignore)]
145 | public int? BadgeAddNum { get; set; }
146 |
147 | [JsonProperty("badge_set_num", NullValueHandling = NullValueHandling.Ignore)]
148 | public int? BadgeSetNum { get; set; }
149 |
150 | [JsonProperty("test_message", NullValueHandling = NullValueHandling.Ignore)]
151 | public bool? TestMessage { get; set; }
152 |
153 | [JsonProperty("receipt_id", NullValueHandling = NullValueHandling.Ignore)]
154 | public string ReceiptId { get; set; }
155 |
156 | [JsonProperty("extras", NullValueHandling = NullValueHandling.Ignore)]
157 | public Dictionary Extras { get; set; }
158 |
159 | [JsonProperty("style", NullValueHandling = NullValueHandling.Ignore)]
160 | public int? Style { get; set; }
161 |
162 | [JsonProperty("inbox", NullValueHandling = NullValueHandling.Ignore)]
163 | public Dictionary Inbox { get; set; }
164 |
165 | [JsonProperty("push_type", NullValueHandling = NullValueHandling.Ignore)]
166 | public int? PushType { get; set; }
167 |
168 | [JsonProperty("extra_data", NullValueHandling = NullValueHandling.Ignore)]
169 | public string ExtraData { get; set; }
170 |
171 | }
172 |
173 | }
174 |
--------------------------------------------------------------------------------
/Jiguang.JPush/ReportClient.cs:
--------------------------------------------------------------------------------
1 | using Jiguang.JPush.Model;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Net.Http;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Jiguang.JPush
10 | {
11 | public class ReportClient
12 | {
13 | public const string BASE_URL_REPORT_DEFAULT = "https://report.jpush.cn/v3";
14 | public const string BASE_URL_REPORT_BEIJING = "https://bjapi.push.jiguang.cn/v3/report";
15 |
16 | private string BASE_URL = BASE_URL_REPORT_DEFAULT;
17 |
18 | ///
19 | /// 设置 Report API 的调用地址。
20 | ///
21 | ///
22 | /// or
23 | public void SetBaseURL(string url)
24 | {
25 | BASE_URL = url;
26 | }
27 |
28 | ///
29 | ///
30 | ///
31 | public async Task GetMessageReportAsync(List msgIdList)
32 | {
33 | if (msgIdList == null)
34 | throw new ArgumentNullException(nameof(msgIdList));
35 |
36 | var msgIds = string.Join(",", msgIdList);
37 | var url = BASE_URL + "/received?msg_ids=" + msgIds;
38 | HttpResponseMessage msg = await JPushClient.HttpClient.GetAsync(url).ConfigureAwait(false);
39 | var content = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
40 | return new HttpResponse(msg.StatusCode, msg.Headers, content);
41 | }
42 |
43 | ///
44 | /// 获取指定 msg_id 的消息送达统计数据。
45 | ///
46 | /// 消息的 msg_id 列表,每次最多支持 100 个。
47 | public HttpResponse GetMessageReport(List msgIdList)
48 | {
49 | Task task = Task.Run(() => GetMessageReportAsync(msgIdList));
50 | task.Wait();
51 | return task.Result;
52 | }
53 |
54 | ///
55 | ///
56 | ///
57 | public async Task GetReceivedDetailReportAsync(List msgIdList)
58 | {
59 | if (msgIdList == null)
60 | throw new ArgumentNullException(nameof(msgIdList));
61 |
62 | var msgIds = string.Join(",", msgIdList);
63 | var url = BASE_URL + "/received/detail?msg_ids=" + msgIds;
64 | HttpResponseMessage msg = await JPushClient.HttpClient.GetAsync(url).ConfigureAwait(false);
65 | var content = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
66 | return new HttpResponse(msg.StatusCode, msg.Headers, content);
67 | }
68 |
69 | ///
70 | /// 送达统计详情(新)
71 | ///
72 | ///
73 | /// 消息的 msg_id 列表,每次最多支持 100 个。
74 | public HttpResponse GetReceivedDetailReport(List msgIdList)
75 | {
76 | Task task = Task.Run(() => GetReceivedDetailReportAsync(msgIdList));
77 | task.Wait();
78 | return task.Result;
79 | }
80 |
81 | ///
82 | ///
83 | ///
84 | public async Task GetMessageSendStatusAsync(string msgId, List registrationIdList, string data)
85 | {
86 | if (string.IsNullOrEmpty(msgId))
87 | throw new ArgumentNullException(nameof(msgId));
88 |
89 | if (registrationIdList == null)
90 | throw new ArgumentNullException(nameof(registrationIdList));
91 |
92 | JObject body = new JObject
93 | {
94 | { "msg_id", long.Parse(msgId) },
95 | { "registration_ids", JArray.FromObject(registrationIdList) }
96 | };
97 |
98 | if (!string.IsNullOrEmpty(data))
99 | body.Add("data", data);
100 |
101 | var url = BASE_URL + "/status/message";
102 | var httpContent = new StringContent(body.ToString(), Encoding.UTF8);
103 |
104 | HttpResponseMessage msg = await JPushClient.HttpClient.PostAsync(url, httpContent).ConfigureAwait(false);
105 | var content = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
106 | return new HttpResponse(msg.StatusCode, msg.Headers, content);
107 | }
108 |
109 | ///
110 | /// 查询指定消息的送达状态。
111 | ///
112 | ///
113 | /// 待查询消息的 Message Id。
114 | /// 收到消息设备的 Registration Id 列表。
115 | /// 待查询日期,格式为 yyyy-MM-dd。如果传 null,则默认为当天。
116 | public HttpResponse GetMessageSendStatus(string msgId, List registrationIdList, string data)
117 | {
118 | Task task = Task.Run(() => GetMessageSendStatusAsync(msgId, registrationIdList, data));
119 | task.Wait();
120 | return task.Result;
121 | }
122 |
123 | ///
124 | ///
125 | ///
126 | public async Task GetMessageDetailReportAsync(List msgIdList)
127 | {
128 | if (msgIdList == null)
129 | throw new ArgumentNullException(nameof(msgIdList));
130 |
131 | var msgIds = string.Join(",", msgIdList);
132 | var url = BASE_URL + "/messages?msg_ids=" + msgIds;
133 | HttpResponseMessage msg = await JPushClient.HttpClient.GetAsync(url).ConfigureAwait(false);
134 | var content = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
135 | return new HttpResponse(msg.StatusCode, msg.Headers, content);
136 | }
137 |
138 | ///
139 | /// 消息统计(VIP 专属接口,旧)
140 | ///
141 | ///
142 | /// 消息的 msg_id 列表,每次最多支持 100 个。
143 | public HttpResponse GetMessageDetailReport(List msgIdList)
144 | {
145 | Task task = Task.Run(() => GetMessageDetailReportAsync(msgIdList));
146 | task.Wait();
147 | return task.Result;
148 | }
149 |
150 | ///
151 | ///
152 | ///
153 | public async Task GetMessagesDetailReportAsync(List msgIdList)
154 | {
155 | if (msgIdList == null)
156 | throw new ArgumentNullException(nameof(msgIdList));
157 |
158 | var msgIds = string.Join(",", msgIdList);
159 | var url = BASE_URL + "/messages/detail?msg_ids=" + msgIds;
160 | HttpResponseMessage msg = await JPushClient.HttpClient.GetAsync(url).ConfigureAwait(false);
161 | var content = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
162 | return new HttpResponse(msg.StatusCode, msg.Headers, content);
163 | }
164 |
165 | ///
166 | /// 消息统计详情(VIP 专属接口,新)
167 | ///
168 | ///
169 | /// 消息的 msg_id 列表,每次最多支持 100 个。
170 | public HttpResponse GetMessagesDetailReport(List msgIdList)
171 | {
172 | Task task = Task.Run(() => GetMessagesDetailReportAsync(msgIdList));
173 | task.Wait();
174 | return task.Result;
175 | }
176 |
177 | ///
178 | ///
179 | ///
180 | public async Task GetUserReportAsync(string timeUnit, string startTime, int duration)
181 | {
182 | if (string.IsNullOrEmpty(timeUnit))
183 | throw new ArgumentNullException(nameof(timeUnit));
184 |
185 | if (startTime == null)
186 | throw new ArgumentNullException(nameof(startTime));
187 |
188 | if (duration <= 0)
189 | throw new ArgumentOutOfRangeException(nameof(duration));
190 |
191 | var url = BASE_URL + "/users?time_unit=" + timeUnit + "&start=" + startTime + "&duration=" + duration;
192 | HttpResponseMessage msg = await JPushClient.HttpClient.GetAsync(url).ConfigureAwait(false);
193 | var content = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
194 | return new HttpResponse(msg.StatusCode, msg.Headers, content);
195 | }
196 |
197 | ///
198 | /// 提供近2个月内某时间段的用户相关统计数据:新增用户、在线用户、活跃用户(VIP only)。
199 | ///
200 | ///
201 | /// 时间单位。支持 "HOUR", "DAY" 或 "MOUNTH"
202 | ///
203 | /// 起始时间。
204 | /// 如果单位是小时,则起始时间是小时(包含天),格式例:2014-06-11 09
205 | /// 如果单位是天,则起始时间是日期(天),格式例:2014-06-11
206 | /// 如果单位是月,则起始时间是日期(月),格式例:2014-06
207 | ///
208 | ///
209 | /// 持续时长。
210 | /// 如果时间单位(timeUnit)是天,则是持续的天数,其他时间单位以此类推。
211 | /// 只支持查询 60 天以内的用户信息。如果 timeUnit 为 HOUR,则只会输出当天的统计结果。
212 | ///
213 | public HttpResponse GetUserReport(string timeUnit, string startTime, int duration)
214 | {
215 | Task task = Task.Run(() => GetUserReportAsync(timeUnit, startTime, duration));
216 | task.Wait();
217 | return task.Result;
218 | }
219 | }
220 | }
221 |
--------------------------------------------------------------------------------
/Jiguang.JPush/JPushClient.cs:
--------------------------------------------------------------------------------
1 | using Jiguang.JPush.Model;
2 | using System;
3 | using System.Net.Http;
4 | using System.Net.Http.Headers;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Collections.Generic;
8 | using Newtonsoft.Json;
9 | using Newtonsoft.Json.Linq;
10 |
11 | namespace Jiguang.JPush
12 | {
13 | public class JPushClient
14 | {
15 | public const string BASE_URL_PUSH_DEFAULT = "https://api.jpush.cn/v3/push";
16 | public const string BASE_URL_PUSH_BEIJING = "https://bjapi.push.jiguang.cn/v3/push";
17 |
18 | private string BASE_URL = BASE_URL_PUSH_DEFAULT;
19 |
20 | public DeviceClient Device;
21 | public ScheduleClient Schedule;
22 | private ReportClient report;
23 |
24 | public ReportClient Report { get => report; set => report = value; }
25 |
26 | public static HttpClient HttpClient;
27 |
28 | static JPushClient()
29 | {
30 | HttpClient = new HttpClient();
31 | HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
32 | }
33 |
34 | public JPushClient(string appKey, string masterSecret)
35 | {
36 | if (string.IsNullOrEmpty(appKey))
37 | throw new ArgumentNullException(nameof(appKey));
38 |
39 | if (string.IsNullOrEmpty(masterSecret))
40 | throw new ArgumentNullException(nameof(masterSecret));
41 |
42 | var auth = Convert.ToBase64String(Encoding.UTF8.GetBytes(appKey + ":" + masterSecret));
43 | HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", auth);
44 |
45 | Report = new ReportClient();
46 | Device = new DeviceClient();
47 | Schedule = new ScheduleClient();
48 | }
49 |
50 | ///
51 | /// 设置 push 功能的 API 调用地址。
52 | ///
53 | /// 如果极光应用分配在北京机房(极光控制台 “应用设置” -> “应用信息” 中可以看到),并且开发者接口调用的服务器也位于北京,则可以调用如下地址:
54 | ///
55 | /// https://bjapi.push.jiguang.cn/v3/push
56 | /// 可以提升 API 的响应速度。
57 | ///
58 | ///
59 | /// or
60 | public void SetBaseURL(string url)
61 | {
62 | BASE_URL = url;
63 | }
64 |
65 | public async Task SendPushAsync(string jsonBody)
66 | {
67 | if (string.IsNullOrEmpty(jsonBody))
68 | throw new ArgumentNullException(nameof(jsonBody));
69 |
70 | HttpContent httpContent = new StringContent(jsonBody, Encoding.UTF8);
71 | HttpResponseMessage msg = await HttpClient.PostAsync(BASE_URL, httpContent).ConfigureAwait(false);
72 | var content = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
73 | return new HttpResponse(msg.StatusCode, msg.Headers, content);
74 | }
75 |
76 | ///
77 | ///
78 | ///
79 | public async Task SendPushAsync(PushPayload payload)
80 | {
81 | if (payload == null)
82 | throw new ArgumentNullException(nameof(payload));
83 |
84 | string body = payload.ToString();
85 | return await SendPushAsync(body);
86 | }
87 |
88 | ///
89 | /// 进行消息推送。
90 | ///
91 | ///
92 | /// 推送对象。
93 | public HttpResponse SendPush(PushPayload pushPayload)
94 | {
95 | Task task = Task.Run(() => SendPushAsync(pushPayload));
96 | task.Wait();
97 | return task.Result;
98 | }
99 |
100 | public async Task IsPushValidAsync(string jsonBody)
101 | {
102 | if (string.IsNullOrEmpty(jsonBody))
103 | throw new ArgumentNullException(nameof(jsonBody));
104 |
105 | HttpContent httpContent = new StringContent(jsonBody, Encoding.UTF8);
106 | var url = BASE_URL + "/validate";
107 | HttpResponseMessage msg = await HttpClient.PostAsync(url, httpContent).ConfigureAwait(false);
108 | var content = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
109 | return new HttpResponse(msg.StatusCode, msg.Headers, content);
110 | }
111 |
112 | ///
113 | ///
114 | ///
115 | public async Task IsPushValidAsync(PushPayload payload)
116 | {
117 | if (payload == null)
118 | throw new ArgumentNullException(nameof(payload));
119 |
120 | var body = payload.ToString();
121 | return await IsPushValidAsync(body);
122 | }
123 |
124 | ///
125 | /// 校验推送能否成功。与推送 API 的区别在于:不会实际向用户发送任何消息。 其他字段说明和推送 API 完全相同。
126 | ///
127 | /// 推送对象。
128 | public HttpResponse IsPushValid(PushPayload pushPayload)
129 | {
130 | Task task = Task.Run(() => IsPushValidAsync(pushPayload));
131 | task.Wait();
132 | return task.Result;
133 | }
134 |
135 | ///
136 | ///
137 | ///
138 | public async Task GetCIdListAsync(int? count, string type)
139 | {
140 | if (count != null && count < 1 && count > 1000)
141 | throw new ArgumentOutOfRangeException(nameof(count));
142 |
143 | var url = BASE_URL + "/cid";
144 |
145 | if (count != null)
146 | {
147 | url += ("?count=" + count);
148 |
149 | if (!string.IsNullOrEmpty(type))
150 | url += ("&type=" + type);
151 | }
152 |
153 | HttpResponseMessage msg = await HttpClient.GetAsync(url).ConfigureAwait(false);
154 | var content = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
155 | return new HttpResponse(msg.StatusCode, msg.Headers, content);
156 | }
157 |
158 | ///
159 | /// 获取 CId(推送的唯一标识符) 列表。
160 | ///
161 | ///
162 | /// 不传默认为 1。范围为[1, 1000]
163 | /// CId 的类型。取值:"push" (默认) 或 "schedule"
164 | public HttpResponse GetCIdList(int? count, string type)
165 | {
166 | Task task = Task.Run(() => GetCIdListAsync(count, type));
167 | task.Wait();
168 | return task.Result;
169 | }
170 |
171 | ///
172 | /// 针对RegID方式批量单推(VIP专属接口)
173 | /// 如果您在给每个用户的推送内容都不同的情况下,可以使用此接口。
174 | ///
175 | ///
176 | /// 批量单推的载体列表
177 | public async Task BatchPushByRegidAsync(List singlePayLoadList)
178 | {
179 | var url = BASE_URL + "/batch/regid/single";
180 | return await BatchPushAsync(url, singlePayLoadList);
181 | }
182 |
183 | ///
184 | /// 针对RegID方式批量单推(VIP专属接口)
185 | /// 如果您在给每个用户的推送内容都不同的情况下,可以使用此接口。
186 | ///
187 | ///
188 | /// 批量单推的载体列表
189 | public HttpResponse BatchPushByRegid(List singlePayLoadList)
190 | {
191 | Task task = Task.Run(() => BatchPushByRegidAsync(singlePayLoadList));
192 | task.Wait();
193 | return task.Result;
194 | }
195 |
196 | ///
197 | /// 针对Alias方式批量单推(VIP专属接口)
198 | /// 如果您在给每个用户的推送内容都不同的情况下,可以使用此接口。
199 | ///
200 | ///
201 | /// 批量单推的载体列表
202 | public async Task BatchPushByAliasAsync(List singlePayLoadList)
203 | {
204 | var url = BASE_URL + "/batch/alias/single";
205 | return await BatchPushAsync(url, singlePayLoadList);
206 | }
207 |
208 | ///
209 | /// 针对Alias方式批量单推(VIP专属接口)
210 | /// 如果您在给每个用户的推送内容都不同的情况下,可以使用此接口。
211 | ///
212 | ///
213 | /// 批量单推的载体列表
214 | public HttpResponse BatchPushByAlias(List singlePayLoadList)
215 | {
216 | Task task = Task.Run(() => BatchPushByAliasAsync(singlePayLoadList));
217 | task.Wait();
218 | return task.Result;
219 | }
220 |
221 | private async Task BatchPushAsync(String url, List singlePayLoadList)
222 | {
223 | HttpResponse cidResponse = await this.GetCIdListAsync(singlePayLoadList.Count, "push");
224 | JObject jObject = (JObject) JsonConvert.DeserializeObject(cidResponse.Content);
225 | JArray jArray = ((JArray) jObject["cidlist"]);
226 | BatchPushPayload batchPushPayload = new BatchPushPayload();
227 | batchPushPayload.Pushlist = new Dictionary();
228 | for (int i = 0; i < singlePayLoadList.Count; i++)
229 | {
230 | batchPushPayload.Pushlist.Add((String) jArray[i], singlePayLoadList[i]);
231 | }
232 | HttpContent httpContent = new StringContent(batchPushPayload.ToString(), Encoding.UTF8);
233 | HttpResponseMessage msg = await HttpClient.PostAsync(url, httpContent).ConfigureAwait(false);
234 | var content = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
235 | return new HttpResponse(msg.StatusCode, msg.Headers, content);
236 | }
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/csharp,visualstudio
3 |
4 | ### Csharp ###
5 | ## Ignore Visual Studio temporary files, build results, and
6 | ## files generated by popular Visual Studio add-ons.
7 | ##
8 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
9 |
10 | # User-specific files
11 | *.suo
12 | *.user
13 | *.userosscache
14 | *.sln.docstates
15 |
16 | # User-specific files (MonoDevelop/Xamarin Studio)
17 | *.userprefs
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | bld/
27 | [Bb]in/
28 | [Oo]bj/
29 | [Ll]og/
30 |
31 | # Visual Studio 2015 cache/options directory
32 | .vs/
33 | # Uncomment if you have tasks that create the project's static files in wwwroot
34 | #wwwroot/
35 |
36 | # MSTest test Results
37 | [Tt]est[Rr]esult*/
38 | [Bb]uild[Ll]og.*
39 |
40 | # NUNIT
41 | *.VisualState.xml
42 | TestResult.xml
43 |
44 | # Build Results of an ATL Project
45 | [Dd]ebugPS/
46 | [Rr]eleasePS/
47 | dlldata.c
48 |
49 | # .NET Core
50 | project.lock.json
51 | project.fragment.lock.json
52 | artifacts/
53 | **/Properties/launchSettings.json
54 |
55 | *_i.c
56 | *_p.c
57 | *_i.h
58 | *.ilk
59 | *.meta
60 | *.obj
61 | *.pch
62 | *.pdb
63 | *.pgc
64 | *.pgd
65 | *.rsp
66 | *.sbr
67 | *.tlb
68 | *.tli
69 | *.tlh
70 | *.tmp
71 | *.tmp_proj
72 | *.log
73 | *.vspscc
74 | *.vssscc
75 | .builds
76 | *.pidb
77 | *.svclog
78 | *.scc
79 |
80 | # Chutzpah Test files
81 | _Chutzpah*
82 |
83 | # Visual C++ cache files
84 | ipch/
85 | *.aps
86 | *.ncb
87 | *.opendb
88 | *.opensdf
89 | *.sdf
90 | *.cachefile
91 | *.VC.db
92 | *.VC.VC.opendb
93 |
94 | # Visual Studio profiler
95 | *.psess
96 | *.vsp
97 | *.vspx
98 | *.sap
99 |
100 | # TFS 2012 Local Workspace
101 | $tf/
102 |
103 | # Guidance Automation Toolkit
104 | *.gpState
105 |
106 | # ReSharper is a .NET coding add-in
107 | _ReSharper*/
108 | *.[Rr]e[Ss]harper
109 | *.DotSettings.user
110 |
111 | # JustCode is a .NET coding add-in
112 | .JustCode
113 |
114 | # TeamCity is a build add-in
115 | _TeamCity*
116 |
117 | # DotCover is a Code Coverage Tool
118 | *.dotCover
119 |
120 | # Visual Studio code coverage results
121 | *.coverage
122 | *.coveragexml
123 |
124 | # NCrunch
125 | _NCrunch_*
126 | .*crunch*.local.xml
127 | nCrunchTemp_*
128 |
129 | # MightyMoose
130 | *.mm.*
131 | AutoTest.Net/
132 |
133 | # Web workbench (sass)
134 | .sass-cache/
135 |
136 | # Installshield output folder
137 | [Ee]xpress/
138 |
139 | # DocProject is a documentation generator add-in
140 | DocProject/buildhelp/
141 | DocProject/Help/*.HxT
142 | DocProject/Help/*.HxC
143 | DocProject/Help/*.hhc
144 | DocProject/Help/*.hhk
145 | DocProject/Help/*.hhp
146 | DocProject/Help/Html2
147 | DocProject/Help/html
148 |
149 | # Click-Once directory
150 | publish/
151 |
152 | # Publish Web Output
153 | *.[Pp]ublish.xml
154 | *.azurePubxml
155 | # TODO: Comment the next line if you want to checkin your web deploy settings
156 | # but database connection strings (with potential passwords) will be unencrypted
157 | *.pubxml
158 | *.publishproj
159 |
160 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
161 | # checkin your Azure Web App publish settings, but sensitive information contained
162 | # in these scripts will be unencrypted
163 | PublishScripts/
164 |
165 | # NuGet Packages
166 | *.nupkg
167 | # The packages folder can be ignored because of Package Restore
168 | **/packages/*
169 | # except build/, which is used as an MSBuild target.
170 | !**/packages/build/
171 | # Uncomment if necessary however generally it will be regenerated when needed
172 | #!**/packages/repositories.config
173 | # NuGet v3's project.json files produces more ignorable files
174 | *.nuget.props
175 | *.nuget.targets
176 |
177 | # Microsoft Azure Build Output
178 | csx/
179 | *.build.csdef
180 |
181 | # Microsoft Azure Emulator
182 | ecf/
183 | rcf/
184 |
185 | # Windows Store app package directories and files
186 | AppPackages/
187 | BundleArtifacts/
188 | Package.StoreAssociation.xml
189 | _pkginfo.txt
190 |
191 | # Visual Studio cache files
192 | # files ending in .cache can be ignored
193 | *.[Cc]ache
194 | # but keep track of directories ending in .cache
195 | !*.[Cc]ache/
196 |
197 | # Others
198 | ClientBin/
199 | ~$*
200 | *~
201 | *.dbmdl
202 | *.dbproj.schemaview
203 | *.jfm
204 | *.pfx
205 | *.publishsettings
206 | orleans.codegen.cs
207 |
208 | # Since there are multiple workflows, uncomment next line to ignore bower_components
209 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
210 | #bower_components/
211 |
212 | # RIA/Silverlight projects
213 | Generated_Code/
214 |
215 | # Backup & report files from converting an old project file
216 | # to a newer Visual Studio version. Backup files are not needed,
217 | # because we have git ;-)
218 | _UpgradeReport_Files/
219 | Backup*/
220 | UpgradeLog*.XML
221 | UpgradeLog*.htm
222 |
223 | # SQL Server files
224 | *.mdf
225 | *.ldf
226 | *.ndf
227 |
228 | # Business Intelligence projects
229 | *.rdl.data
230 | *.bim.layout
231 | *.bim_*.settings
232 |
233 | # Microsoft Fakes
234 | FakesAssemblies/
235 |
236 | # GhostDoc plugin setting file
237 | *.GhostDoc.xml
238 |
239 | # Node.js Tools for Visual Studio
240 | .ntvs_analysis.dat
241 | node_modules/
242 |
243 | # Typescript v1 declaration files
244 | typings/
245 |
246 | # Visual Studio 6 build log
247 | *.plg
248 |
249 | # Visual Studio 6 workspace options file
250 | *.opt
251 |
252 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
253 | *.vbw
254 |
255 | # Visual Studio LightSwitch build output
256 | **/*.HTMLClient/GeneratedArtifacts
257 | **/*.DesktopClient/GeneratedArtifacts
258 | **/*.DesktopClient/ModelManifest.xml
259 | **/*.Server/GeneratedArtifacts
260 | **/*.Server/ModelManifest.xml
261 | _Pvt_Extensions
262 |
263 | # Paket dependency manager
264 | .paket/paket.exe
265 | paket-files/
266 |
267 | # FAKE - F# Make
268 | .fake/
269 |
270 | # JetBrains Rider
271 | .idea/
272 | *.sln.iml
273 |
274 | # CodeRush
275 | .cr/
276 |
277 | # Python Tools for Visual Studio (PTVS)
278 | __pycache__/
279 | *.pyc
280 |
281 | # Cake - Uncomment if you are using it
282 | # tools/**
283 | # !tools/packages.config
284 |
285 | # Telerik's JustMock configuration file
286 | *.jmconfig
287 |
288 | # BizTalk build output
289 | *.btp.cs
290 | *.btm.cs
291 | *.odx.cs
292 | *.xsd.cs
293 |
294 | ### VisualStudio ###
295 | ## Ignore Visual Studio temporary files, build results, and
296 | ## files generated by popular Visual Studio add-ons.
297 | ##
298 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
299 |
300 | # User-specific files
301 |
302 | # User-specific files (MonoDevelop/Xamarin Studio)
303 |
304 | # Build results
305 |
306 | # Visual Studio 2015 cache/options directory
307 | # Uncomment if you have tasks that create the project's static files in wwwroot
308 | #wwwroot/
309 |
310 | # MSTest test Results
311 |
312 | # NUNIT
313 |
314 | # Build Results of an ATL Project
315 |
316 | # .NET Core
317 |
318 |
319 | # Chutzpah Test files
320 |
321 | # Visual C++ cache files
322 |
323 | # Visual Studio profiler
324 |
325 | # TFS 2012 Local Workspace
326 |
327 | # Guidance Automation Toolkit
328 |
329 | # ReSharper is a .NET coding add-in
330 |
331 | # JustCode is a .NET coding add-in
332 |
333 | # TeamCity is a build add-in
334 |
335 | # DotCover is a Code Coverage Tool
336 |
337 | # Visual Studio code coverage results
338 |
339 | # NCrunch
340 |
341 | # MightyMoose
342 |
343 | # Web workbench (sass)
344 |
345 | # Installshield output folder
346 |
347 | # DocProject is a documentation generator add-in
348 |
349 | # Click-Once directory
350 |
351 | # Publish Web Output
352 | # TODO: Comment the next line if you want to checkin your web deploy settings
353 | # but database connection strings (with potential passwords) will be unencrypted
354 |
355 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
356 | # checkin your Azure Web App publish settings, but sensitive information contained
357 | # in these scripts will be unencrypted
358 |
359 | # NuGet Packages
360 | # The packages folder can be ignored because of Package Restore
361 | # except build/, which is used as an MSBuild target.
362 | # Uncomment if necessary however generally it will be regenerated when needed
363 | #!**/packages/repositories.config
364 | # NuGet v3's project.json files produces more ignorable files
365 |
366 | # Microsoft Azure Build Output
367 |
368 | # Microsoft Azure Emulator
369 |
370 | # Windows Store app package directories and files
371 |
372 | # Visual Studio cache files
373 | # files ending in .cache can be ignored
374 | # but keep track of directories ending in .cache
375 |
376 | # Others
377 |
378 | # Since there are multiple workflows, uncomment next line to ignore bower_components
379 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
380 | #bower_components/
381 |
382 | # RIA/Silverlight projects
383 |
384 | # Backup & report files from converting an old project file
385 | # to a newer Visual Studio version. Backup files are not needed,
386 | # because we have git ;-)
387 |
388 | # SQL Server files
389 |
390 | # Business Intelligence projects
391 |
392 | # Microsoft Fakes
393 |
394 | # GhostDoc plugin setting file
395 |
396 | # Node.js Tools for Visual Studio
397 |
398 | # Typescript v1 declaration files
399 |
400 | # Visual Studio 6 build log
401 |
402 | # Visual Studio 6 workspace options file
403 |
404 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
405 |
406 | # Visual Studio LightSwitch build output
407 |
408 | # Paket dependency manager
409 |
410 | # FAKE - F# Make
411 |
412 | # JetBrains Rider
413 |
414 | # CodeRush
415 |
416 | # Python Tools for Visual Studio (PTVS)
417 |
418 | # Cake - Uncomment if you are using it
419 | # tools/**
420 | # !tools/packages.config
421 |
422 | # Telerik's JustMock configuration file
423 |
424 | # BizTalk build output
425 |
426 | # End of https://www.gitignore.io/api/csharp,visualstudio
427 |
428 | *.nuspec
429 |
430 | NETFrameworkTest/App\.config
431 |
432 | NETFrameworkTest/NETFrameworkTest\.csproj
433 |
434 | NETFrameworkTest/Program\.cs
435 |
436 | NETFrameworkTest/Properties/AssemblyInfo\.cs
437 | /.vscode
438 | /Example/ExampleConfig.cs
439 |
--------------------------------------------------------------------------------
/Jiguang.JPush/DeviceClient.cs:
--------------------------------------------------------------------------------
1 | using Jiguang.JPush.Model;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Net.Http;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Newtonsoft.Json;
8 | using Newtonsoft.Json.Linq;
9 |
10 | namespace Jiguang.JPush
11 | {
12 | public class DeviceClient
13 | {
14 | private const string BASE_URL = "https://device.jpush.cn";
15 |
16 | ///
17 | ///
18 | ///
19 | public async Task GetDeviceInfoAsync(string registrationId)
20 | {
21 | if (string.IsNullOrEmpty(registrationId))
22 | throw new ArgumentNullException(registrationId);
23 |
24 | var url = BASE_URL + "/v3/devices/" + registrationId;
25 | HttpResponseMessage msg = await JPushClient.HttpClient.GetAsync(url).ConfigureAwait(false);
26 | var content = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
27 | return new HttpResponse(msg.StatusCode, msg.Headers, content);
28 | }
29 |
30 | ///
31 | /// 查询指定设备信息。
32 | ///
33 | ///
34 | ///
35 | /// 客户端初始化 JPush 成功后,JPush 服务端会分配一个 Registration ID,作为此设备的标识(同一个手机不同 APP 的 Registration ID 是不同的)。
36 | ///
37 | public HttpResponse GetDeviceInfo(string registrationId)
38 | {
39 | Task task = Task.Run(() => GetDeviceInfoAsync(registrationId));
40 | task.Wait();
41 | return task.Result;
42 | }
43 |
44 | public async Task UpdateDeviceInfoAsync(string registrationId, string json)
45 | {
46 | if (string.IsNullOrEmpty(registrationId))
47 | throw new ArgumentNullException(nameof(registrationId));
48 |
49 | if (string.IsNullOrEmpty(json))
50 | throw new ArgumentNullException(nameof(json));
51 |
52 | var url = BASE_URL + "/v3/devices/" + registrationId;
53 | HttpContent requestContent = new StringContent(json, Encoding.UTF8);
54 | HttpResponseMessage msg = await JPushClient.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false);
55 | string responseContent = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
56 | return new HttpResponse(msg.StatusCode, msg.Headers, responseContent);
57 | }
58 |
59 | ///
60 | ///
61 | ///
62 | public async Task UpdateDeviceInfoAsync(string registrationId, DevicePayload devicePayload)
63 | {
64 | if (string.IsNullOrEmpty(registrationId))
65 | throw new ArgumentNullException(nameof(registrationId));
66 |
67 | if (devicePayload == null)
68 | throw new ArgumentNullException(nameof(devicePayload));
69 |
70 | var json = devicePayload.ToString();
71 | return await UpdateDeviceInfoAsync(registrationId, json);
72 | }
73 |
74 | ///
75 | /// 更新设备信息(目前支持 tag, alias 和 mobile)。
76 | ///
77 | ///
78 | ///
79 | /// 客户端初始化 JPush 成功后,JPush 服务端会分配一个 Registration ID,作为此设备的标识(同一个手机不同 APP 的 Registration ID 是不同的)。
80 | ///
81 | /// 设备信息对象
82 | public HttpResponse UpdateDeviceInfo(string registrationId, DevicePayload devicePayload)
83 | {
84 | Task task = Task.Run(() => UpdateDeviceInfoAsync(registrationId, devicePayload));
85 | task.Wait();
86 | return task.Result;
87 | }
88 |
89 | ///
90 | ///
91 | ///
92 | public async Task GetDevicesByAliasAsync(string alias, string platform)
93 | {
94 | if (string.IsNullOrEmpty(alias))
95 | throw new ArgumentNullException(nameof(alias));
96 |
97 | var url = BASE_URL + "/v3/aliases/" + alias;
98 |
99 | if (!string.IsNullOrEmpty(platform))
100 | url += "?platform=" + platform;
101 |
102 | HttpResponseMessage msg = await JPushClient.HttpClient.GetAsync(url).ConfigureAwait(false);
103 | string responseConetent = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
104 | return new HttpResponse(msg.StatusCode, msg.Headers, responseConetent);
105 | }
106 |
107 | ///
108 | /// 获取指定 alias 下的设备,最多输出 10 个。
109 | ///
110 | ///
111 | /// 要查询的别名(alias)
112 | /// "android" 或 "ios", 为 null 则默认为所有平台。
113 | public HttpResponse GetDeviceByAlias(string alias, string platform)
114 | {
115 | Task task = Task.Run(() => GetDevicesByAliasAsync(alias, platform));
116 | task.Wait();
117 | return task.Result;
118 | }
119 |
120 | ///
121 | ///
122 | ///
123 | public async Task DeleteAliasAsync(string alias, string platform)
124 | {
125 | if (string.IsNullOrEmpty(alias))
126 | throw new ArgumentNullException(alias);
127 |
128 | var url = BASE_URL + "/v3/aliases/" + alias;
129 |
130 | if (!string.IsNullOrEmpty(platform))
131 | url += "?platform=" + platform;
132 |
133 | HttpResponseMessage msg = await JPushClient.HttpClient.DeleteAsync(url).ConfigureAwait(false);
134 | return new HttpResponse(msg.StatusCode, msg.Headers, "");
135 | }
136 |
137 | ///
138 | /// 删除一个别名,以及该别名与设备的绑定关系。
139 | ///
140 | ///
141 | /// 待删除的别名(alias)
142 | /// "android" 或 "ios",为 null 则默认为所有平台。
143 | public HttpResponse DeleteAlias(string alias, string platform)
144 | {
145 | Task task = Task.Run(() => DeleteAliasAsync(alias, platform));
146 | task.Wait();
147 | return task.Result;
148 | }
149 |
150 | ///
151 | ///
152 | ///
153 | public async Task GetTagsAsync()
154 | {
155 | var url = BASE_URL + "/v3/tags/";
156 | HttpResponseMessage msg = await JPushClient.HttpClient.GetAsync(url).ConfigureAwait(false);
157 | string responseContent = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
158 | return new HttpResponse(msg.StatusCode, msg.Headers, responseContent);
159 | }
160 |
161 | ///
162 | /// 获取当前应用的所有标签列表,每个平台最多返回 100 个。
163 | ///
164 | ///
165 | public HttpResponse GetTags()
166 | {
167 | Task task = Task.Run(() => GetTagsAsync());
168 | task.Wait();
169 | return task.Result;
170 | }
171 |
172 | ///
173 | ///
174 | ///
175 | public async Task IsDeviceInTagAsync(string registrationId, string tag)
176 | {
177 | if (string.IsNullOrEmpty(registrationId))
178 | throw new ArgumentNullException(nameof(registrationId));
179 |
180 | if (string.IsNullOrEmpty(tag))
181 | throw new ArgumentNullException(nameof(tag));
182 |
183 | var url = BASE_URL + "/v3/tags/" + tag + "/registration_ids/" + registrationId;
184 | HttpResponseMessage msg = await JPushClient.HttpClient.GetAsync(url).ConfigureAwait(false);
185 | string responseContent = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
186 | return new HttpResponse(msg.StatusCode, msg.Headers, responseContent);
187 | }
188 |
189 | ///
190 | /// 查询某个设备是否在某个 tag 下。
191 | ///
192 | ///
193 | /// 设备的 registration id
194 | /// 要查询的 tag
195 | public HttpResponse IsDeviceInTag(string registrationId, string tag)
196 | {
197 | Task task = Task.Run(() => IsDeviceInTagAsync(registrationId, tag));
198 | task.Wait();
199 | return task.Result;
200 | }
201 |
202 | ///
203 | ///
204 | ///
205 | public async Task AddDevicesToTagAsync(string tag, List registrationIdList)
206 | {
207 | if (string.IsNullOrEmpty(tag))
208 | throw new ArgumentNullException(nameof(tag));
209 |
210 | if (registrationIdList == null || registrationIdList.Count == 0)
211 | throw new ArgumentException(nameof(registrationIdList));
212 |
213 | var url = BASE_URL + "/v3/tags/" + tag;
214 |
215 | JObject jObj = new JObject
216 | {
217 | ["registration_ids"] = new JObject
218 | {
219 | ["add"] = new JArray(registrationIdList)
220 | }
221 | };
222 |
223 | var requestContent = new StringContent(jObj.ToString(), Encoding.UTF8);
224 | HttpResponseMessage msg = await JPushClient.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false);
225 | return new HttpResponse(msg.StatusCode, msg.Headers, "");
226 | }
227 |
228 | ///
229 | /// 为一个标签(tag)添加设备,一次最多支持 1000 个。
230 | ///
231 | ///
232 | /// 待操作的标签(tag)
233 | /// 设备的 registration id 列表
234 | public HttpResponse AddDevicesToTag(string tag, List registrationIdList)
235 | {
236 | Task task = Task.Run(() => AddDevicesToTagAsync(tag, registrationIdList));
237 | task.Wait();
238 | return task.Result;
239 | }
240 |
241 | ///
242 | ///
243 | ///
244 | public async Task RemoveDevicesFromTagAsync(string tag, List registrationIdList)
245 | {
246 | if (string.IsNullOrEmpty(tag))
247 | throw new ArgumentNullException(nameof(tag));
248 |
249 | if (registrationIdList == null || registrationIdList.Count == 0)
250 | throw new ArgumentException(nameof(registrationIdList));
251 |
252 | var url = BASE_URL + "/v3/tags/" + tag;
253 |
254 | JObject jObj = new JObject
255 | {
256 | ["registration_ids"] = new JObject
257 | {
258 | ["remove"] = new JArray(registrationIdList)
259 | }
260 | };
261 |
262 | var requestContent = new StringContent(jObj.ToString(), Encoding.UTF8);
263 | HttpResponseMessage msg = await JPushClient.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false);
264 | return new HttpResponse(msg.StatusCode, msg.Headers, "");
265 | }
266 |
267 | ///
268 | /// 为一个标签移除设备。
269 | ///
270 | ///
271 | /// 待操作的标签(tag)
272 | /// 设备的 registration id 列表
273 | public HttpResponse RemoveDevicesFromTag(string tag, List registrationIdList)
274 | {
275 | Task task = Task.Run(() => RemoveDevicesFromTagAsync(tag, registrationIdList));
276 | task.Wait();
277 | return task.Result;
278 | }
279 |
280 | ///
281 | ///
282 | ///
283 | public async Task DeleteTagAsync(string tag, string platform)
284 | {
285 | if (string.IsNullOrEmpty(tag))
286 | throw new ArgumentNullException(nameof(tag));
287 |
288 | var url = BASE_URL + "/v3/tags/" + tag;
289 |
290 | if (!string.IsNullOrEmpty(platform))
291 | url += "?platform=" + platform;
292 |
293 | HttpResponseMessage msg = await JPushClient.HttpClient.DeleteAsync(url).ConfigureAwait(false);
294 | return new HttpResponse(msg.StatusCode, msg.Headers, "");
295 | }
296 |
297 | ///
298 | /// 删除标签,以及标签与其下设备的关联关系。
299 | ///
300 | ///
301 | /// 待删除标签
302 | /// "android" 或 "ios",如果为 null,则默认为所有平台
303 | public HttpResponse DeleteTag(string tag, string platform)
304 | {
305 | Task task = Task.Run(() => DeleteTagAsync(tag, platform));
306 | task.Wait();
307 | return task.Result;
308 | }
309 |
310 | ///
311 | ///
312 | ///
313 | public async Task GetUserOnlineStatusAsync(List registrationIdList)
314 | {
315 | if (registrationIdList == null || registrationIdList.Count == 0)
316 | throw new ArgumentException(nameof(registrationIdList));
317 |
318 | var url = BASE_URL + "/v3/devices/status/";
319 | JObject jObj = new JObject
320 | {
321 | ["registration_ids"] = new JArray(registrationIdList)
322 |
323 | };
324 |
325 | var requestContent = new StringContent(jObj.ToString(), Encoding.UTF8);
326 |
327 | HttpResponseMessage msg = await JPushClient.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false);
328 | string responseContent = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
329 | return new HttpResponse(msg.StatusCode, msg.Headers, responseContent);
330 | }
331 |
332 | ///
333 | /// 获取用户在线状态(VIP only)。
334 | ///
335 | ///
336 | /// 待查询用户设备的 registration id,每次最多支持 1000 个。
337 | public HttpResponse GetUserOnlineStatus(List registrationIdList)
338 | {
339 | Task task = Task.Run(() => GetUserOnlineStatusAsync(registrationIdList));
340 | task.Wait();
341 | return task.Result;
342 | }
343 | }
344 | }
--------------------------------------------------------------------------------
/Jiguang.JPush/ScheduleClient.cs:
--------------------------------------------------------------------------------
1 | using Jiguang.JPush.Model;
2 | using System.Threading.Tasks;
3 | using System;
4 | using Newtonsoft.Json.Linq;
5 | using System.Net.Http;
6 | using System.Text;
7 | using Newtonsoft.Json;
8 |
9 | namespace Jiguang.JPush
10 | {
11 | public class ScheduleClient
12 | {
13 | public const string BASE_URL_SCHEDULE_DEFAULT = "https://api.jpush.cn/v3/schedules";
14 | public const string BASE_URL_SCHEDULE_BEIJING = "https://bjapi.push.jiguang.cn/v3/push/schedules";
15 |
16 | private string BASE_URL = BASE_URL_SCHEDULE_DEFAULT;
17 |
18 | private JsonSerializer jsonSerializer = new JsonSerializer
19 | {
20 | NullValueHandling = NullValueHandling.Ignore
21 | };
22 |
23 | ///
24 | /// 设置 Schedule API 的调用地址。
25 | ///
26 | /// or
27 | public void SetBaseURL(string url)
28 | {
29 | BASE_URL = url;
30 | }
31 |
32 | ///
33 | /// 创建定时任务。
34 | ///
35 | ///
36 | /// 自己构造的请求 json 字符串。
37 | ///
38 | ///
39 | public async Task CreateScheduleTaskAsync(string json)
40 | {
41 | if (string.IsNullOrEmpty(json))
42 | throw new ArgumentNullException(nameof(json));
43 |
44 | HttpContent requestContent = new StringContent(json, Encoding.UTF8);
45 | HttpResponseMessage msg = await JPushClient.HttpClient.PostAsync(BASE_URL, requestContent).ConfigureAwait(false);
46 | string responseContent = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
47 | return new HttpResponse(msg.StatusCode, msg.Headers, responseContent);
48 | }
49 |
50 | ///
51 | ///
52 | ///
53 | public async Task CreateSingleScheduleTaskAsync(string name, PushPayload pushPayload, string triggeringTime)
54 | {
55 | if (string.IsNullOrEmpty(name))
56 | throw new ArgumentNullException(nameof(name));
57 |
58 | if (pushPayload == null)
59 | throw new ArgumentNullException(nameof(pushPayload));
60 |
61 | if (string.IsNullOrEmpty(triggeringTime))
62 | throw new ArgumentNullException(nameof(triggeringTime));
63 |
64 | JObject requestJson = new JObject
65 | {
66 | ["name"] = name,
67 | ["enabled"] = true,
68 | ["push"] = JObject.FromObject(pushPayload, jsonSerializer),
69 | ["trigger"] = new JObject
70 | {
71 | ["single"] = new JObject
72 | {
73 | ["time"] = triggeringTime
74 | }
75 | }
76 | };
77 |
78 | return await CreateScheduleTaskAsync(requestJson.ToString()).ConfigureAwait(false);
79 | }
80 |
81 | ///
82 | /// 创建单次定时任务。
83 | ///
84 | /// 表示 schedule 任务的名字,由 schedule-api 在用户成功创建 schedule 任务后返回,不得超过 255 字节,由汉字、字母、数字、下划线组成。
85 | /// 推送对象
86 | /// 触发器
87 | public HttpResponse CreateSingleScheduleTask(string name, PushPayload pushPayload, string triggeringTime)
88 | {
89 | Task task = Task.Run(() => CreateSingleScheduleTaskAsync(name, pushPayload, triggeringTime));
90 | task.Wait();
91 | return task.Result;
92 | }
93 |
94 | ///
95 | ///
96 | ///
97 | public async Task CreatePeriodicalScheduleTaskAsync(string name, PushPayload pushPayload, Trigger trigger)
98 | {
99 | if (string.IsNullOrEmpty(name))
100 | throw new ArgumentNullException(nameof(name));
101 |
102 | if (pushPayload == null)
103 | throw new ArgumentNullException(nameof(pushPayload));
104 |
105 | if (trigger == null)
106 | throw new ArgumentNullException(nameof(trigger));
107 |
108 | JObject requestJson = new JObject
109 | {
110 | ["name"] = name,
111 | ["enabled"] = true,
112 | ["push"] = JObject.FromObject(pushPayload, jsonSerializer),
113 | ["trigger"] = new JObject()
114 | {
115 | ["periodical"] = JObject.FromObject(trigger)
116 | }
117 | };
118 |
119 | return await CreateScheduleTaskAsync(requestJson.ToString()).ConfigureAwait(false);
120 | }
121 |
122 | ///
123 | /// 创建会在一段时间内重复执行的定期任务。
124 | ///
125 | ///
126 | /// 表示 schedule 任务的名字,由 schedule-api 在用户成功创建 schedule 任务后返回,不得超过 255 字节,由汉字、字母、数字、下划线组成。
127 | /// 推送对象
128 | /// 触发器
129 | public HttpResponse CreatePeriodicalScheduleTask(string name, PushPayload pushPayload, Trigger trigger)
130 | {
131 | Task task = Task.Run(() => CreatePeriodicalScheduleTaskAsync(name, pushPayload, trigger));
132 | task.Wait();
133 | return task.Result;
134 | }
135 |
136 | ///
137 | ///
138 | ///
139 | public async Task GetValidScheduleTasksAsync(int page = 1)
140 | {
141 | if (page <= 0)
142 | throw new ArgumentNullException(nameof(page));
143 |
144 | var url = BASE_URL + "?page=" + page;
145 | HttpResponseMessage msg = await JPushClient.HttpClient.GetAsync(url).ConfigureAwait(false);
146 | string responseContent = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
147 | return new HttpResponse(msg.StatusCode, msg.Headers, responseContent);
148 | }
149 |
150 | ///
151 | /// 获取有效的定时任务列表。
152 | ///
153 | ///
154 | /// 返回当前请求页的详细的 schedule-task 列表,如未指定 page 则 page 为 1。
155 | /// 排序规则:创建时间,由 schedule-service 完成。
156 | /// 如果请求页数大于总页数,则 page 为请求值,schedules 为空。
157 | /// 每页最多返回 50 个 task,如请求页实际的 task 的个数小于 50,则返回实际数量的 task。
158 | ///
159 | public HttpResponse GetValidScheduleTasks(int page = 1)
160 | {
161 | Task task = Task.Run(() => GetValidScheduleTasksAsync(page));
162 | task.Wait();
163 | return task.Result;
164 | }
165 |
166 | ///
167 | ///
168 | ///
169 | public async Task GetScheduleTaskAsync(string scheduleId)
170 | {
171 | if (string.IsNullOrEmpty(scheduleId))
172 | throw new ArgumentNullException(nameof(scheduleId));
173 |
174 | var url = BASE_URL + $"/{scheduleId}";
175 | HttpResponseMessage msg = await JPushClient.HttpClient.GetAsync(url).ConfigureAwait(false);
176 | string responseContent = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
177 | return new HttpResponse(msg.StatusCode, msg.Headers, responseContent);
178 | }
179 |
180 | ///
181 | /// 获取指定的定时任务。
182 | ///
183 | /// 定时任务 ID。在创建定时任务时会返回。
184 | public HttpResponse GetScheduleTask(string scheduleId)
185 | {
186 | Task task = Task.Run(() => GetScheduleTaskAsync(scheduleId));
187 | task.Wait();
188 | return task.Result;
189 | }
190 |
191 |
192 | ///
193 | ///
194 | ///
195 | public async Task GetScheduleTaskMsgIdAsync(string scheduleId)
196 | {
197 | if (string.IsNullOrEmpty(scheduleId))
198 | throw new ArgumentNullException(nameof(scheduleId));
199 |
200 | var url = BASE_URL + $"/{scheduleId}/msg_ids";
201 | HttpResponseMessage msg = await JPushClient.HttpClient.GetAsync(url).ConfigureAwait(false);
202 | string responseContent = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
203 | return new HttpResponse(msg.StatusCode, msg.Headers, responseContent);
204 | }
205 |
206 | ///
207 | /// 获取定时任务对应的所有 msg_id。
208 | ///
209 | /// 定时任务 ID。在创建定时任务时会返回。
210 | public HttpResponse GetScheduleTaskMsgId(string scheduleId)
211 | {
212 | Task task = Task.Run(() => GetScheduleTaskMsgIdAsync(scheduleId));
213 | task.Wait();
214 | return task.Result;
215 | }
216 |
217 | public async Task UpdateScheduleTaskAsync(string scheduleId, string json)
218 | {
219 | if (string.IsNullOrEmpty(scheduleId))
220 | throw new ArgumentNullException(nameof(scheduleId));
221 |
222 | if (string.IsNullOrEmpty(json))
223 | throw new ArgumentNullException(nameof(json));
224 |
225 | var url = BASE_URL + $"/{scheduleId}";
226 | HttpContent requestContent = new StringContent(json, Encoding.UTF8);
227 | HttpResponseMessage msg = await JPushClient.HttpClient.PutAsync(url, requestContent).ConfigureAwait(false);
228 | string responseContent = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
229 | return new HttpResponse(msg.StatusCode, msg.Headers, responseContent);
230 | }
231 |
232 | ///
233 | ///
234 | ///
235 | public async Task UpdateSingleScheduleTaskAsync(string scheduleId, string name, bool? enabled,
236 | string triggeringTime, PushPayload pushPayload)
237 | {
238 | if (string.IsNullOrEmpty(scheduleId))
239 | throw new ArgumentNullException(scheduleId);
240 |
241 | JObject json = new JObject();
242 |
243 | if (!string.IsNullOrEmpty(name))
244 | json["name"] = name;
245 |
246 | if (enabled != null)
247 | json["enabled"] = enabled;
248 |
249 | if (triggeringTime != null)
250 | {
251 | json["trigger"] = new JObject
252 | {
253 | ["single"] = new JObject
254 | {
255 | ["time"] = triggeringTime
256 | }
257 | };
258 | }
259 |
260 | if (pushPayload != null)
261 | {
262 | json["push"] = JObject.FromObject(pushPayload, jsonSerializer);
263 | }
264 |
265 | return await UpdateScheduleTaskAsync(scheduleId, json.ToString()).ConfigureAwait(false);
266 | }
267 |
268 | ///
269 | /// 更新单次定时任务。
270 | ///
271 | /// 任务 ID
272 | /// 任务名称,为 null 表示不更新。
273 | /// 是否可用,为 null 表示不更新。
274 | /// 触发时间,类似 "2017-08-03 12:00:00",为 null 表示不更新。
275 | /// 推送内容,为 null 表示不更新。
276 | public HttpResponse UpdateSingleScheduleTask(string scheduleId, string name, bool? enabled, string triggeringTime, PushPayload pushPayload)
277 | {
278 | Task task = Task.Run(() => UpdateSingleScheduleTaskAsync(scheduleId, name, enabled, triggeringTime, pushPayload));
279 | task.Wait();
280 | return task.Result;
281 | }
282 |
283 | ///
284 | ///
285 | ///
286 | public async Task UpdatePeriodicalScheduleTaskAsync(string scheduleId, string name, bool? enabled,
287 | Trigger trigger, PushPayload pushPayload)
288 | {
289 | if (string.IsNullOrEmpty(scheduleId))
290 | throw new ArgumentNullException(scheduleId);
291 |
292 | JObject json = new JObject();
293 |
294 | if (!string.IsNullOrEmpty(name))
295 | json["name"] = name;
296 |
297 | if (enabled != null)
298 | json["enabled"] = enabled;
299 |
300 | if (trigger != null)
301 | {
302 | json["trigger"] = new JObject
303 | {
304 | ["periodical"] = JObject.FromObject(trigger, jsonSerializer)
305 | };
306 | }
307 |
308 | if (pushPayload != null)
309 | {
310 | json["push"] = JObject.FromObject(pushPayload, jsonSerializer);
311 | }
312 |
313 | return await UpdateScheduleTaskAsync(scheduleId, json.ToString()).ConfigureAwait(false);
314 | }
315 |
316 | ///
317 | /// 更新会重复执行的定时任务。
318 | ///
319 | ///
320 | /// 任务 ID
321 | /// 任务名称,为 null 表示不更新。
322 | /// 是否可用,为 null 表示不更新。
323 | /// 触发器对象,为 null 表示不更新。
324 | /// 推送内容,为 null 表示不更新。
325 | public HttpResponse UpdatePeriodicalScheduleTask(string scheduleId, string name, bool? enabled, Trigger trigger, PushPayload pushPayload)
326 | {
327 | Task task = Task.Run(() => UpdatePeriodicalScheduleTaskAsync(scheduleId, name, enabled, trigger, pushPayload));
328 | task.Wait();
329 | return task.Result;
330 | }
331 |
332 | ///
333 | ///
334 | ///
335 | public async Task DeleteScheduleTaskAsync(string scheduleId)
336 | {
337 | if (string.IsNullOrEmpty(scheduleId))
338 | throw new ArgumentNullException(nameof(scheduleId));
339 |
340 | var url = BASE_URL + $"/{scheduleId}";
341 | HttpResponseMessage msg = await JPushClient.HttpClient.DeleteAsync(url).ConfigureAwait(false);
342 | string responseContent = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
343 | return new HttpResponse(msg.StatusCode, msg.Headers, responseContent);
344 | }
345 |
346 | ///
347 | /// 删除指定的定时任务。
348 | ///
349 | ///
350 | /// 已创建的 schedule 任务的 id。如果 scheduleId 不合法,即不是有效的 uuid,则返回 404。
351 | public HttpResponse DeleteScheduleTask(string scheduleId)
352 | {
353 | Task task = Task.Run(() => DeleteScheduleTaskAsync(scheduleId));
354 | task.Wait();
355 | return task.Result;
356 | }
357 | }
358 | }
359 |
--------------------------------------------------------------------------------