├── .gitignore
├── APNsKit.xcodeproj
├── APNsKit.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── APNsKit.xcscmblueprint
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── APNsKit.xcscmblueprint
└── xcshareddata
│ └── xcschemes
│ └── APNsKit.xcscheme
├── APNsKit.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── APNsKit.xcscmblueprint
├── APNsKit
├── APNsKit.h
├── APNsPayload.swift
├── APNsPort.swift
├── APNsRequest.swift
├── APNsServer.swift
├── Connection.swift
├── Info.plist
├── Main.storyboard
├── PKCS12Adapter.swift
└── PushViewController.playground
│ ├── Contents.swift
│ ├── Sources
│ └── PushViewController.swift
│ └── contents.xcplayground
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode (from gitignore.io)
2 | build/
3 | *.pbxuser
4 | !default.pbxuser
5 | *.mode1v3
6 | !default.mode1v3
7 | *.mode2v3
8 | !default.mode2v3
9 | *.perspectivev3
10 | !default.perspectivev3
11 | xcuserdata
12 | *.xccheckout
13 | *.moved-aside
14 | DerivedData
15 | *.hmap
16 | *.ipa
17 | *.xcuserstate
18 |
19 | # others
20 | *.swp
21 | !.gitkeep
22 | .DS_Store
23 |
--------------------------------------------------------------------------------
/APNsKit.xcodeproj/APNsKit.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/APNsKit.xcodeproj/APNsKit.xcworkspace/xcshareddata/APNsKit.xcscmblueprint:
--------------------------------------------------------------------------------
1 | {
2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "3DA82495CA2199B9C34A4BAB2FB2ACDDD02CA769",
3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4 |
5 | },
6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7 | "3DA82495CA2199B9C34A4BAB2FB2ACDDD02CA769" : 9223372036854775807,
8 | "CA86F53ED6CB060B09097483BD033980A4C323F8" : 9223372036854775807
9 | },
10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "05E42A2B-40F8-4295-A7A4-C15C0F9F496D",
11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
12 | "3DA82495CA2199B9C34A4BAB2FB2ACDDD02CA769" : "APNsKit\/",
13 | "CA86F53ED6CB060B09097483BD033980A4C323F8" : ""
14 | },
15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "APNsKit",
16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204,
17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "APNsKit.xcodeproj",
18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
19 | {
20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:hagmas\/APNsKit.git",
21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "3DA82495CA2199B9C34A4BAB2FB2ACDDD02CA769"
23 | },
24 | {
25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:hagmas\/Parrot.git",
26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "CA86F53ED6CB060B09097483BD033980A4C323F8"
28 | }
29 | ]
30 | }
--------------------------------------------------------------------------------
/APNsKit.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | C0644ABE1E78394600334798 /* APNsKit.h in Headers */ = {isa = PBXBuildFile; fileRef = C0644ABC1E78394600334798 /* APNsKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | C0644ACA1E783A7000334798 /* APNsPayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0644AC41E783A7000334798 /* APNsPayload.swift */; };
12 | C0644ACB1E783A7000334798 /* APNsPort.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0644AC51E783A7000334798 /* APNsPort.swift */; };
13 | C0644ACC1E783A7000334798 /* APNsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0644AC61E783A7000334798 /* APNsRequest.swift */; };
14 | C0644ACD1E783A7000334798 /* APNsServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0644AC71E783A7000334798 /* APNsServer.swift */; };
15 | C0644ACE1E783A7000334798 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0644AC81E783A7000334798 /* Connection.swift */; };
16 | C0644ACF1E783A7000334798 /* PKCS12Adapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0644AC91E783A7000334798 /* PKCS12Adapter.swift */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXFileReference section */
20 | C0644AB91E78394600334798 /* APNsKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = APNsKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
21 | C0644ABC1E78394600334798 /* APNsKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = APNsKit.h; sourceTree = ""; };
22 | C0644ABD1E78394600334798 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
23 | C0644AC41E783A7000334798 /* APNsPayload.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APNsPayload.swift; sourceTree = ""; };
24 | C0644AC51E783A7000334798 /* APNsPort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APNsPort.swift; sourceTree = ""; };
25 | C0644AC61E783A7000334798 /* APNsRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APNsRequest.swift; sourceTree = ""; };
26 | C0644AC71E783A7000334798 /* APNsServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APNsServer.swift; sourceTree = ""; };
27 | C0644AC81E783A7000334798 /* Connection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Connection.swift; sourceTree = ""; };
28 | C0644AC91E783A7000334798 /* PKCS12Adapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PKCS12Adapter.swift; sourceTree = ""; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | C0644AB51E78394600334798 /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | );
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXFrameworksBuildPhase section */
40 |
41 | /* Begin PBXGroup section */
42 | C0644AAF1E78394600334798 = {
43 | isa = PBXGroup;
44 | children = (
45 | C0644ABB1E78394600334798 /* APNsKit */,
46 | C0644ABA1E78394600334798 /* Products */,
47 | );
48 | sourceTree = "";
49 | };
50 | C0644ABA1E78394600334798 /* Products */ = {
51 | isa = PBXGroup;
52 | children = (
53 | C0644AB91E78394600334798 /* APNsKit.framework */,
54 | );
55 | name = Products;
56 | sourceTree = "";
57 | };
58 | C0644ABB1E78394600334798 /* APNsKit */ = {
59 | isa = PBXGroup;
60 | children = (
61 | C0644ABC1E78394600334798 /* APNsKit.h */,
62 | C0644ABD1E78394600334798 /* Info.plist */,
63 | C0644AC41E783A7000334798 /* APNsPayload.swift */,
64 | C0644AC51E783A7000334798 /* APNsPort.swift */,
65 | C0644AC61E783A7000334798 /* APNsRequest.swift */,
66 | C0644AC71E783A7000334798 /* APNsServer.swift */,
67 | C0644AC81E783A7000334798 /* Connection.swift */,
68 | C0644AC91E783A7000334798 /* PKCS12Adapter.swift */,
69 | );
70 | path = APNsKit;
71 | sourceTree = "";
72 | };
73 | /* End PBXGroup section */
74 |
75 | /* Begin PBXHeadersBuildPhase section */
76 | C0644AB61E78394600334798 /* Headers */ = {
77 | isa = PBXHeadersBuildPhase;
78 | buildActionMask = 2147483647;
79 | files = (
80 | C0644ABE1E78394600334798 /* APNsKit.h in Headers */,
81 | );
82 | runOnlyForDeploymentPostprocessing = 0;
83 | };
84 | /* End PBXHeadersBuildPhase section */
85 |
86 | /* Begin PBXNativeTarget section */
87 | C0644AB81E78394600334798 /* APNsKit */ = {
88 | isa = PBXNativeTarget;
89 | buildConfigurationList = C0644AC11E78394600334798 /* Build configuration list for PBXNativeTarget "APNsKit" */;
90 | buildPhases = (
91 | C0644AB41E78394600334798 /* Sources */,
92 | C0644AB51E78394600334798 /* Frameworks */,
93 | C0644AB61E78394600334798 /* Headers */,
94 | C0644AB71E78394600334798 /* Resources */,
95 | );
96 | buildRules = (
97 | );
98 | dependencies = (
99 | );
100 | name = APNsKit;
101 | productName = APNsKit;
102 | productReference = C0644AB91E78394600334798 /* APNsKit.framework */;
103 | productType = "com.apple.product-type.framework";
104 | };
105 | /* End PBXNativeTarget section */
106 |
107 | /* Begin PBXProject section */
108 | C0644AB01E78394600334798 /* Project object */ = {
109 | isa = PBXProject;
110 | attributes = {
111 | LastUpgradeCheck = 0820;
112 | ORGANIZATIONNAME = "Haga Masaki";
113 | TargetAttributes = {
114 | C0644AB81E78394600334798 = {
115 | CreatedOnToolsVersion = 8.2.1;
116 | ProvisioningStyle = Automatic;
117 | };
118 | };
119 | };
120 | buildConfigurationList = C0644AB31E78394600334798 /* Build configuration list for PBXProject "APNsKit" */;
121 | compatibilityVersion = "Xcode 3.2";
122 | developmentRegion = English;
123 | hasScannedForEncodings = 0;
124 | knownRegions = (
125 | en,
126 | );
127 | mainGroup = C0644AAF1E78394600334798;
128 | productRefGroup = C0644ABA1E78394600334798 /* Products */;
129 | projectDirPath = "";
130 | projectRoot = "";
131 | targets = (
132 | C0644AB81E78394600334798 /* APNsKit */,
133 | );
134 | };
135 | /* End PBXProject section */
136 |
137 | /* Begin PBXResourcesBuildPhase section */
138 | C0644AB71E78394600334798 /* Resources */ = {
139 | isa = PBXResourcesBuildPhase;
140 | buildActionMask = 2147483647;
141 | files = (
142 | );
143 | runOnlyForDeploymentPostprocessing = 0;
144 | };
145 | /* End PBXResourcesBuildPhase section */
146 |
147 | /* Begin PBXSourcesBuildPhase section */
148 | C0644AB41E78394600334798 /* Sources */ = {
149 | isa = PBXSourcesBuildPhase;
150 | buildActionMask = 2147483647;
151 | files = (
152 | C0644ACD1E783A7000334798 /* APNsServer.swift in Sources */,
153 | C0644ACF1E783A7000334798 /* PKCS12Adapter.swift in Sources */,
154 | C0644ACB1E783A7000334798 /* APNsPort.swift in Sources */,
155 | C0644ACE1E783A7000334798 /* Connection.swift in Sources */,
156 | C0644ACC1E783A7000334798 /* APNsRequest.swift in Sources */,
157 | C0644ACA1E783A7000334798 /* APNsPayload.swift in Sources */,
158 | );
159 | runOnlyForDeploymentPostprocessing = 0;
160 | };
161 | /* End PBXSourcesBuildPhase section */
162 |
163 | /* Begin XCBuildConfiguration section */
164 | C0644ABF1E78394600334798 /* Debug */ = {
165 | isa = XCBuildConfiguration;
166 | buildSettings = {
167 | ALWAYS_SEARCH_USER_PATHS = NO;
168 | CLANG_ANALYZER_NONNULL = YES;
169 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
170 | CLANG_CXX_LIBRARY = "libc++";
171 | CLANG_ENABLE_MODULES = YES;
172 | CLANG_ENABLE_OBJC_ARC = YES;
173 | CLANG_WARN_BOOL_CONVERSION = YES;
174 | CLANG_WARN_CONSTANT_CONVERSION = YES;
175 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
176 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
177 | CLANG_WARN_EMPTY_BODY = YES;
178 | CLANG_WARN_ENUM_CONVERSION = YES;
179 | CLANG_WARN_INFINITE_RECURSION = YES;
180 | CLANG_WARN_INT_CONVERSION = YES;
181 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
182 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
183 | CLANG_WARN_UNREACHABLE_CODE = YES;
184 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
185 | CODE_SIGN_IDENTITY = "-";
186 | COPY_PHASE_STRIP = NO;
187 | CURRENT_PROJECT_VERSION = 1;
188 | DEBUG_INFORMATION_FORMAT = dwarf;
189 | ENABLE_STRICT_OBJC_MSGSEND = YES;
190 | ENABLE_TESTABILITY = YES;
191 | GCC_C_LANGUAGE_STANDARD = gnu99;
192 | GCC_DYNAMIC_NO_PIC = NO;
193 | GCC_NO_COMMON_BLOCKS = YES;
194 | GCC_OPTIMIZATION_LEVEL = 0;
195 | GCC_PREPROCESSOR_DEFINITIONS = (
196 | "DEBUG=1",
197 | "$(inherited)",
198 | );
199 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
200 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
201 | GCC_WARN_UNDECLARED_SELECTOR = YES;
202 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
203 | GCC_WARN_UNUSED_FUNCTION = YES;
204 | GCC_WARN_UNUSED_VARIABLE = YES;
205 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
206 | MACOSX_DEPLOYMENT_TARGET = 10.12;
207 | MTL_ENABLE_DEBUG_INFO = YES;
208 | ONLY_ACTIVE_ARCH = YES;
209 | SDKROOT = macosx;
210 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator watchos watchsimulator appletvos appletvsimulator";
211 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
212 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
213 | VERSIONING_SYSTEM = "apple-generic";
214 | VERSION_INFO_PREFIX = "";
215 | };
216 | name = Debug;
217 | };
218 | C0644AC01E78394600334798 /* Release */ = {
219 | isa = XCBuildConfiguration;
220 | buildSettings = {
221 | ALWAYS_SEARCH_USER_PATHS = NO;
222 | CLANG_ANALYZER_NONNULL = YES;
223 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
224 | CLANG_CXX_LIBRARY = "libc++";
225 | CLANG_ENABLE_MODULES = YES;
226 | CLANG_ENABLE_OBJC_ARC = YES;
227 | CLANG_WARN_BOOL_CONVERSION = YES;
228 | CLANG_WARN_CONSTANT_CONVERSION = YES;
229 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
230 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
231 | CLANG_WARN_EMPTY_BODY = YES;
232 | CLANG_WARN_ENUM_CONVERSION = YES;
233 | CLANG_WARN_INFINITE_RECURSION = YES;
234 | CLANG_WARN_INT_CONVERSION = YES;
235 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
236 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
237 | CLANG_WARN_UNREACHABLE_CODE = YES;
238 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
239 | CODE_SIGN_IDENTITY = "-";
240 | COPY_PHASE_STRIP = NO;
241 | CURRENT_PROJECT_VERSION = 1;
242 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
243 | ENABLE_NS_ASSERTIONS = NO;
244 | ENABLE_STRICT_OBJC_MSGSEND = YES;
245 | GCC_C_LANGUAGE_STANDARD = gnu99;
246 | GCC_NO_COMMON_BLOCKS = YES;
247 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
248 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
249 | GCC_WARN_UNDECLARED_SELECTOR = YES;
250 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
251 | GCC_WARN_UNUSED_FUNCTION = YES;
252 | GCC_WARN_UNUSED_VARIABLE = YES;
253 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
254 | MACOSX_DEPLOYMENT_TARGET = 10.12;
255 | MTL_ENABLE_DEBUG_INFO = NO;
256 | SDKROOT = macosx;
257 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator watchos watchsimulator appletvos appletvsimulator";
258 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
259 | VERSIONING_SYSTEM = "apple-generic";
260 | VERSION_INFO_PREFIX = "";
261 | };
262 | name = Release;
263 | };
264 | C0644AC21E78394600334798 /* Debug */ = {
265 | isa = XCBuildConfiguration;
266 | buildSettings = {
267 | CODE_SIGN_IDENTITY = "";
268 | COMBINE_HIDPI_IMAGES = YES;
269 | DEFINES_MODULE = YES;
270 | DYLIB_COMPATIBILITY_VERSION = 1;
271 | DYLIB_CURRENT_VERSION = 1;
272 | DYLIB_INSTALL_NAME_BASE = "@rpath";
273 | FRAMEWORK_VERSION = A;
274 | INFOPLIST_FILE = APNsKit/Info.plist;
275 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
276 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
277 | PRODUCT_BUNDLE_IDENTIFIER = masaki.haga.APNsKit;
278 | PRODUCT_NAME = "$(TARGET_NAME)";
279 | SDKROOT = iphoneos10.2;
280 | SKIP_INSTALL = YES;
281 | SWIFT_VERSION = 3.0;
282 | };
283 | name = Debug;
284 | };
285 | C0644AC31E78394600334798 /* Release */ = {
286 | isa = XCBuildConfiguration;
287 | buildSettings = {
288 | CODE_SIGN_IDENTITY = "";
289 | COMBINE_HIDPI_IMAGES = YES;
290 | DEFINES_MODULE = YES;
291 | DYLIB_COMPATIBILITY_VERSION = 1;
292 | DYLIB_CURRENT_VERSION = 1;
293 | DYLIB_INSTALL_NAME_BASE = "@rpath";
294 | FRAMEWORK_VERSION = A;
295 | INFOPLIST_FILE = APNsKit/Info.plist;
296 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
297 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
298 | PRODUCT_BUNDLE_IDENTIFIER = masaki.haga.APNsKit;
299 | PRODUCT_NAME = "$(TARGET_NAME)";
300 | SDKROOT = iphoneos10.2;
301 | SKIP_INSTALL = YES;
302 | SWIFT_VERSION = 3.0;
303 | };
304 | name = Release;
305 | };
306 | /* End XCBuildConfiguration section */
307 |
308 | /* Begin XCConfigurationList section */
309 | C0644AB31E78394600334798 /* Build configuration list for PBXProject "APNsKit" */ = {
310 | isa = XCConfigurationList;
311 | buildConfigurations = (
312 | C0644ABF1E78394600334798 /* Debug */,
313 | C0644AC01E78394600334798 /* Release */,
314 | );
315 | defaultConfigurationIsVisible = 0;
316 | defaultConfigurationName = Release;
317 | };
318 | C0644AC11E78394600334798 /* Build configuration list for PBXNativeTarget "APNsKit" */ = {
319 | isa = XCConfigurationList;
320 | buildConfigurations = (
321 | C0644AC21E78394600334798 /* Debug */,
322 | C0644AC31E78394600334798 /* Release */,
323 | );
324 | defaultConfigurationIsVisible = 0;
325 | defaultConfigurationName = Release;
326 | };
327 | /* End XCConfigurationList section */
328 | };
329 | rootObject = C0644AB01E78394600334798 /* Project object */;
330 | }
331 |
--------------------------------------------------------------------------------
/APNsKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/APNsKit.xcodeproj/project.xcworkspace/xcshareddata/APNsKit.xcscmblueprint:
--------------------------------------------------------------------------------
1 | {
2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "3DA82495CA2199B9C34A4BAB2FB2ACDDD02CA769",
3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4 |
5 | },
6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7 | "3DA82495CA2199B9C34A4BAB2FB2ACDDD02CA769" : 9223372036854775807,
8 | "CA86F53ED6CB060B09097483BD033980A4C323F8" : 9223372036854775807
9 | },
10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "05E42A2B-40F8-4295-A7A4-C15C0F9F496D",
11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
12 | "3DA82495CA2199B9C34A4BAB2FB2ACDDD02CA769" : "APNsKit\/",
13 | "CA86F53ED6CB060B09097483BD033980A4C323F8" : ""
14 | },
15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "APNsKit",
16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204,
17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "APNsKit.xcodeproj",
18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
19 | {
20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:hagmas\/APNsKit.git",
21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "3DA82495CA2199B9C34A4BAB2FB2ACDDD02CA769"
23 | },
24 | {
25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:hagmas\/Parrot.git",
26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "CA86F53ED6CB060B09097483BD033980A4C323F8"
28 | }
29 | ]
30 | }
--------------------------------------------------------------------------------
/APNsKit.xcodeproj/xcshareddata/xcschemes/APNsKit.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
73 |
75 |
76 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/APNsKit.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/APNsKit.xcworkspace/xcshareddata/APNsKit.xcscmblueprint:
--------------------------------------------------------------------------------
1 | {
2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "D65E0F9E3FEB7C912C4B67B9F8ACCEDB6B38A9EA",
3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4 |
5 | },
6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7 | "D65E0F9E3FEB7C912C4B67B9F8ACCEDB6B38A9EA" : 9223372036854775807,
8 | "CA86F53ED6CB060B09097483BD033980A4C323F8" : 9223372036854775807
9 | },
10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "05E42A2B-40F8-4295-A7A4-C15C0F9F496D",
11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
12 | "D65E0F9E3FEB7C912C4B67B9F8ACCEDB6B38A9EA" : "APNsKit\/",
13 | "CA86F53ED6CB060B09097483BD033980A4C323F8" : ""
14 | },
15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "APNsKit",
16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204,
17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "APNsKit.xcworkspace",
18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
19 | {
20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:hagmas\/Parrot.git",
21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "CA86F53ED6CB060B09097483BD033980A4C323F8"
23 | },
24 | {
25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:hagmas\/APNsKit.git",
26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "D65E0F9E3FEB7C912C4B67B9F8ACCEDB6B38A9EA"
28 | }
29 | ]
30 | }
--------------------------------------------------------------------------------
/APNsKit/APNsKit.h:
--------------------------------------------------------------------------------
1 | //
2 | // APNsKit.h
3 | // APNsKit
4 | //
5 | // Created by Haga Masaki on 14/03/2017.
6 | // Copyright © 2017 Haga Masaki. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for APNsKit.
12 | FOUNDATION_EXPORT double APNsKitVersionNumber;
13 |
14 | //! Project version string for APNsKit.
15 | FOUNDATION_EXPORT const unsigned char APNsKitVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/APNsKit/APNsPayload.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public struct APNsPayload {
4 | let title: String?
5 | let body: String
6 | let titleLocKey: String?
7 | let titleLocArgs: [String]?
8 | let actionLocKey: String?
9 | let locKey: String?
10 | let locArgs: [String]?
11 | let launchImage: String?
12 |
13 | let badge: Int?
14 | let sound: String?
15 | let contentAvailable: Int?
16 | let mutableContent: Int?
17 | let category: String?
18 | let threadId: String?
19 |
20 | let custom: [String: Any]?
21 |
22 | public init(
23 | title: String? = nil,
24 | body: String,
25 | titleLocKey: String? = nil,
26 | titleLocArgs: [String]? = nil,
27 | actionLocKey: String? = nil,
28 | locKey: String? = nil,
29 | locArgs: [String]? = nil,
30 | launchImage: String? = nil,
31 |
32 | badge: Int? = nil,
33 | sound: String? = nil,
34 | contentAvailable: Int? = nil,
35 | mutableContent: Int? = nil,
36 | category: String? = nil,
37 | threadId: String? = nil,
38 |
39 | custom: [String: Any]? = nil) {
40 | self.title = title
41 | self.body = body
42 | self.titleLocKey = titleLocKey
43 | self.titleLocArgs = titleLocArgs
44 | self.actionLocKey = actionLocKey
45 | self.locKey = locKey
46 | self.locArgs = locArgs
47 | self.launchImage = launchImage
48 |
49 | self.badge = badge
50 | self.sound = sound
51 | self.contentAvailable = contentAvailable
52 | self.mutableContent = mutableContent
53 | self.category = category
54 | self.threadId = threadId
55 |
56 | self.custom = custom
57 | }
58 |
59 | public var dictionary: [String: Any] {
60 | // Alert
61 | var alert: [String: Any] = ["body": body]
62 |
63 | if let title = title {
64 | alert["title"] = title
65 | }
66 |
67 | if let titleLocKey = titleLocKey {
68 | alert["title-loc-key"] = titleLocKey
69 | }
70 |
71 | if let titleLocArgs = titleLocArgs {
72 | alert["title-loc-args"] = titleLocArgs
73 | }
74 |
75 | if let actionLocKey = actionLocKey {
76 | alert["action-loc-key"] = actionLocKey
77 | }
78 |
79 | if let locKey = locKey {
80 | alert["loc-key"] = locKey
81 | }
82 |
83 | if let locArgs = locArgs {
84 | alert["loc-args"] = locArgs
85 | }
86 |
87 | if let launchImage = launchImage {
88 | alert["launch-image"] = launchImage
89 | }
90 |
91 | // APS
92 | var dictionary: [String: Any] = ["alert": alert]
93 |
94 | if let badge = badge {
95 | dictionary["badge"] = badge
96 | }
97 |
98 | if let sound = sound {
99 | dictionary["sound"] = sound
100 | }
101 |
102 | if let contentAvailable = contentAvailable {
103 | dictionary["content-available"] = contentAvailable
104 | }
105 |
106 | if let mutableContent = mutableContent {
107 | dictionary["mutable-content"] = mutableContent
108 | }
109 |
110 | if let category = category {
111 | dictionary["category"] = category
112 | }
113 |
114 | if let threadId = threadId {
115 | dictionary["thread-id"] = threadId
116 | }
117 |
118 | var payload: [String: Any] = ["aps": dictionary]
119 |
120 | // Custom
121 | custom?.forEach {
122 | payload[$0] = $1
123 | }
124 |
125 | return payload
126 | }
127 |
128 | public static func convert(parameters: Any) -> String {
129 | if let dictionary = parameters as? [String: Any] {
130 | return "{" + dictionary.map { "\"\($0.key)\":" + convert(parameters: $0.value) }.joined(separator: ",") + "}"
131 | } else if let array = parameters as? [String] {
132 | return "[" + array.joined(separator: ",") + "]"
133 | } else if let int = parameters as? Int {
134 | return "\(int)"
135 | } else {
136 | return "\"\(parameters)\""
137 | }
138 | }
139 |
140 | public var data: Data? {
141 | return APNsPayload.convert(parameters: dictionary).data(using: .unicode)
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/APNsKit/APNsPort.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public enum APNsPort: Int {
4 | case p443 = 443
5 | case p2197 = 2197
6 | }
7 |
--------------------------------------------------------------------------------
/APNsKit/APNsRequest.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public struct APNsRequest {
4 | public struct Header {
5 | public enum Priority: String {
6 | case p5 = "5", p10 = "10"
7 | }
8 |
9 | public let id: String
10 | public let expiration: Date
11 | public let priority: Priority
12 | public let topic: String?
13 | public let collapseId: String?
14 |
15 | public init(id: String = UUID().uuidString,
16 | expiration: Date = Date(timeIntervalSince1970: 0),
17 | priority: Priority = .p10,
18 | topic: String? = nil,
19 | collapseId: String? = nil) {
20 | self.id = id
21 | self.expiration = expiration
22 | self.priority = .p10
23 | self.topic = topic
24 | self.collapseId = collapseId
25 | }
26 | }
27 |
28 | public var port: APNsPort
29 | public var server: APNsServer
30 | public var deviceToken: String
31 | public var header: Header
32 | public var payload: APNsPayload
33 |
34 | public static let method = "POST"
35 |
36 | public init(port: APNsPort, server: APNsServer, deviceToken: String, header: Header = Header(), payload: APNsPayload) {
37 | self.port = port
38 | self.server = server
39 | self.deviceToken = deviceToken
40 | self.header = header
41 | self.payload = payload
42 | }
43 |
44 | public var url: URL? {
45 | let urlString = "https://" + server.rawValue + ":\(port.rawValue)" + "/3/device/" + deviceToken
46 | return URL(string: urlString)
47 | }
48 |
49 | public var urlRequest: URLRequest? {
50 | guard let url = url else {
51 | return nil
52 | }
53 |
54 | var request = URLRequest(url: url)
55 | request.setValue(for: header)
56 | request.httpMethod = APNsRequest.method
57 | request.httpBody = payload.data
58 | return request
59 | }
60 | }
61 |
62 | private extension URLRequest {
63 | mutating func setValue(for header: APNsRequest.Header) {
64 | self.addValue(header.id, forHTTPHeaderField: "apns-id")
65 | self.addValue("\(Int(header.expiration.timeIntervalSince1970))", forHTTPHeaderField: "apns-expiration")
66 | self.addValue(header.priority.rawValue, forHTTPHeaderField: "apns-priority")
67 |
68 | if let topic = header.topic {
69 | self.addValue(topic, forHTTPHeaderField: "apns-topic")
70 | }
71 |
72 | if let collapseId = header.collapseId {
73 | self.addValue(collapseId, forHTTPHeaderField: "apns-collapse-id")
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/APNsKit/APNsServer.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public enum APNsServer: String {
4 | case development = "api.development.push.apple.com"
5 | case production = "api.push.apple.com"
6 | }
7 |
--------------------------------------------------------------------------------
/APNsKit/Connection.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public class Connection: NSObject, URLSessionDelegate {
4 | public enum Result {
5 | case success
6 | case failure(errorCode: Int, message: String)
7 | }
8 |
9 | let adapter: PKCS12Adapter
10 |
11 | public init(p12FileName: String, passPhrase: String) throws {
12 | self.adapter = try PKCS12Adapter(fileName: p12FileName, passPhrase: passPhrase)
13 | super.init()
14 | }
15 |
16 | public func send(request: APNsRequest, resultHandler: @escaping (Result) -> Void) {
17 | let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil)
18 | if let urlRequest = request.urlRequest {
19 | let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
20 | // The APNs server response for the requst is returned with the data object.
21 | // If the error object is not nil, there is more likely a problem with the connection or the network.
22 | if let error = error {
23 | resultHandler(.failure(errorCode: 0, message: "Unkonwn Error Occured: \(error)"))
24 | return
25 | }
26 |
27 | guard let data = data else {
28 | resultHandler(.success)
29 | return
30 | }
31 |
32 | if data.isEmpty {
33 | resultHandler(.success)
34 | return
35 | }
36 |
37 | if let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: String],
38 | let reason = json?["reason"],
39 | let httpResponse = response as? HTTPURLResponse {
40 | resultHandler(.failure(errorCode: httpResponse.statusCode, message: reason))
41 | return
42 | } else {
43 | resultHandler(.failure(errorCode: 0, message: "Unkonwn Error Occured"))
44 | return
45 | }
46 | })
47 | task.resume()
48 | }
49 | }
50 |
51 | public func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
52 | // Nothing to do
53 | }
54 |
55 | #if os(iOS) || os(watchOS) || os(tvOS)
56 | public func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
57 | // Nothing to do
58 | }
59 | #endif
60 |
61 | public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
62 | switch challenge.protectionSpace.authenticationMethod {
63 | case NSURLAuthenticationMethodClientCertificate:
64 | let credential = URLCredential(identity: adapter.secIdentity, certificates: [adapter.secCertificate], persistence: .forSession)
65 | completionHandler(.useCredential, credential)
66 |
67 | case NSURLAuthenticationMethodServerTrust:
68 | if let serverTrust = challenge.protectionSpace.serverTrust {
69 | let credential = URLCredential(trust: serverTrust)
70 | completionHandler(.useCredential, credential)
71 | }
72 |
73 | default:
74 | break
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/APNsKit/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 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSHumanReadableCopyright
22 | Copyright © 2017 Haga Masaki. All rights reserved.
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/APNsKit/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/APNsKit/PKCS12Adapter.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Security
3 |
4 | enum PKCS12AdapterError: Error {
5 | case unknown
6 | case fileNotFound
7 | case fileOpenFailed
8 | case secAuthFailed
9 | }
10 |
11 | public struct PKCS12Adapter {
12 |
13 | public let secCertificate: SecCertificate
14 | public let secIdentity: SecIdentity
15 |
16 | public init(fileName: String, passPhrase: String) throws {
17 | guard let path = Bundle.main.path(forResource: fileName, ofType: "p12") else {
18 | throw PKCS12AdapterError.fileNotFound
19 | }
20 |
21 | guard let pkcs12data = NSData(contentsOfFile: path) else {
22 | throw PKCS12AdapterError.fileOpenFailed
23 | }
24 |
25 | let options = [String(kSecImportExportPassphrase): passPhrase]
26 | var imported: CFArray? = nil
27 |
28 | switch SecPKCS12Import(pkcs12data, options as CFDictionary, &imported) {
29 | case noErr:
30 | let identityDictionaries = imported as! [[String:Any]]
31 | let identityRef = identityDictionaries[0][kSecImportItemIdentity as String] as! SecIdentity
32 |
33 | var _certRef: SecCertificate?
34 | SecIdentityCopyCertificate(identityRef, &_certRef)
35 |
36 | guard let certRef = _certRef else {
37 | throw PKCS12AdapterError.unknown
38 | }
39 |
40 | self.secCertificate = certRef
41 | self.secIdentity = identityRef
42 |
43 | case errSecAuthFailed:
44 | throw PKCS12AdapterError.secAuthFailed
45 |
46 | default:
47 | throw PKCS12AdapterError.unknown
48 | }
49 | }
50 |
51 | public var sslCertificates: [Any] {
52 | return [secIdentity, secCertificate]
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/APNsKit/PushViewController.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 |
3 | # How to use this playground
4 |
5 | 1. Build the framework with the target "Generic iOS Device".
6 | 2. Create the provider client certificate. (Follow the steps described [here](https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppDistributionGuide/AddingCapabilities/AddingCapabilities.html#//apple_ref/doc/uid/TP40012582-CH26-SW11))
7 | 3. Export your identity from the keychain app in the Personal Information Exchange Format (.p12) and place it under the Resources folder of this playground.
8 | 4. Fill port number, developement/production server, the device token of the target device, the name of the p12 file and its pass phrase.
9 | 5. You will see a view on the playground timeline and push the button to send notifications.
10 | */
11 |
12 | import UIKit
13 | import APNsKit
14 | import PlaygroundSupport
15 |
16 | PlaygroundPage.current.needsIndefiniteExecution = true
17 | URLCache.shared = URLCache(memoryCapacity: 0, diskCapacity: 0, diskPath: nil)
18 |
19 | let payload = APNsPayload(body: "Hello, World!")
20 | let request = APNsRequest(port: <#port#>,
21 | server: <#server#>,
22 | deviceToken: <#deviceToken#>,
23 | payload: payload)
24 |
25 | let pushVC: PushViewController
26 | if let _pushVC = PushViewController(p12FileName: <#p12FileName#>,
27 | passPhrase: <#passPhrase#>,
28 | request: request) {
29 | pushVC = _pushVC
30 | pushVC.view.frame = CGRect(x: 0, y: 0, width: 414, height: 736)
31 | PlaygroundPage.current.liveView = pushVC
32 | }
33 |
--------------------------------------------------------------------------------
/APNsKit/PushViewController.playground/Sources/PushViewController.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import UIKit
3 | import APNsKit
4 |
5 | public class PushViewController: UIViewController {
6 |
7 | let pushButton = UIButton(type: .system)
8 |
9 | let connection: Connection
10 | let request: APNsRequest
11 |
12 | public init?(p12FileName: String, passPhrase: String, request: APNsRequest) {
13 | do {
14 | let connection = try Connection(p12FileName: p12FileName, passPhrase: passPhrase)
15 | self.connection = connection
16 | self.request = request
17 | super.init(nibName: nil, bundle: nil)
18 | } catch {
19 | print("Failed to create connection: \(error)")
20 | return nil
21 | }
22 | }
23 |
24 | required public init?(coder aDecoder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 |
28 | override public func loadView() {
29 | super.loadView()
30 |
31 | view.backgroundColor = UIColor.white
32 |
33 | view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
34 | pushButton.setTitle( "⚡️Push⚡️", for: .normal)
35 | pushButton.titleLabel?.font = UIFont.systemFont(ofSize: 30.0)
36 | pushButton.sizeToFit()
37 | pushButton.translatesAutoresizingMaskIntoConstraints = false
38 | pushButton.addTarget(self, action: #selector(pushed), for: .touchUpInside)
39 | view.addSubview(pushButton)
40 |
41 | pushButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
42 | pushButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
43 | }
44 |
45 | func pushed() {
46 | connection.send(request: request) {
47 | switch $0 {
48 | case .success:
49 | print("Succeeded!")
50 | case .failure(let errorCode, let message):
51 | print("Failed to push! \(errorCode), \(message)")
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/APNsKit/PushViewController.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Masaki Haga
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 all
13 | 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 THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # APNsKit
2 | A framework to send Apple notifications.
3 |
4 | [](https://github.com/Carthage/Carthage)
5 |
6 | ## About APNsKit
7 | APNsKit is a swift framework to send Apple notifications to iOS devices. Especially, with Playground it lets you to create interactive tool to send push notifications for debugging purposes. Check out the Playground `PushViewController.playground` bundled with the Workspace.
8 |
9 |
10 | ## Usage
11 | ```swift
12 | import APNsKit
13 |
14 | // Setting header fields is optional. Refer (#1) for configurable header fields of APNs request.
15 | let header = APNsRequest.Header(priority: .p10, topic: "<#The topic of the remote notification#>")
16 |
17 | // Create a APNs payload. See Apple's Payload Key Reference (#2) for its specifications.
18 | let payload = APNsPayload(title: "Hello World!", body: "This is APNsKit.", contentAvailable: 1)
19 | let request = APNsRequest(port: .p2197,
20 | server: .development,
21 | deviceToken: "<#The target device token#>",
22 | header: header,
23 | payload: payload)
24 |
25 | // Create a connection that wraps up URLSession and its authentication challenges.
26 | if let connection = try? Connection(p12FileName: "<#Your p12 file name#>", passPhrase: "<#The pass phrase for the file#>") {
27 |
28 | // Send the request to the APNs server. The connection has to be retained until the server responses.
29 | connection.send(request: request, resultHandler: { result in
30 | switch result {
31 | case .success:
32 | print("Succeeded!")
33 | case .failure(let code, let message):
34 | print("Failed to send: \(code), \(message)")
35 | }
36 | })
37 | }
38 | ```
39 | #1 [HTTP/2 Request to APNs](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW11)
40 |
41 | #2 [Apple's Payload Key Reference](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html#//apple_ref/doc/uid/TP40008194-CH17-SW1)
42 |
43 | ## Requirements
44 | * Xcode 8.2.1
45 | * Swift 3.0
46 |
47 | ## Installation
48 | * APNsKit doesn't include any external depenancies.
49 | * APNsKit currently supports only Carthage.
50 | ### [Carthage](https://github.com/Carthage/Carthage)
51 |
52 | **Tested with `carthage version`: `0.20.1`**
53 |
54 | Add this to `Cartfile`
55 |
56 | ```
57 | github "hagmas/APNsKit"
58 | ```
59 |
60 | ```bash
61 | $ carthage update
62 | ```
63 |
--------------------------------------------------------------------------------