@amityco/social-plus-vise 0.14.28 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/README.md +6 -11
- package/dist/tools/ast.js +153 -28
- package/dist/tools/docs.js +48 -0
- package/dist/tools/sdkFacts.js +45 -1
- package/docs-cache/README.md +34 -0
- package/docs-cache/social-plus-sdk/core-concepts/foundation/logging.mdx +236 -0
- package/docs-cache/social-plus-sdk/core-concepts/realtime-communication/live-objects-collections/android.mdx +262 -0
- package/docs-cache/social-plus-sdk/core-concepts/realtime-communication/live-objects-collections/flutter.mdx +195 -0
- package/docs-cache/social-plus-sdk/core-concepts/realtime-communication/live-objects-collections/ios.mdx +452 -0
- package/docs-cache/social-plus-sdk/core-concepts/realtime-communication/live-objects-collections/overview.mdx +133 -0
- package/docs-cache/social-plus-sdk/core-concepts/realtime-communication/live-objects-collections/typescript.mdx +264 -0
- package/docs-cache/social-plus-sdk/core-concepts/realtime-communication/push-notifications/register-and-unregister-push-notifications-on-a-device.mdx +191 -0
- package/docs-cache/social-plus-sdk/core-concepts/realtime-communication/push-notifications/settings/overview.mdx +43 -0
- package/docs-cache/social-plus-sdk/core-concepts/realtime-communication/push-notifications/setup/android-setup.mdx +360 -0
- package/docs-cache/social-plus-sdk/core-concepts/realtime-communication/push-notifications/setup/flutter-setup.mdx +457 -0
- package/docs-cache/social-plus-sdk/core-concepts/realtime-communication/push-notifications/setup/ios-setup.mdx +423 -0
- package/docs-cache/social-plus-sdk/core-concepts/realtime-communication/push-notifications/setup/react-native-setup.mdx +384 -0
- package/docs-cache/social-plus-sdk/core-concepts/realtime-communication/realtime-events/overview.mdx +94 -0
- package/docs-cache/social-plus-sdk/getting-started/authentication.mdx +808 -0
- package/docs-cache/social-plus-sdk/getting-started/platform-setup/mobile/android-quick-start.mdx +304 -0
- package/docs-cache/social-plus-sdk/getting-started/platform-setup/mobile/flutter-quick-start.mdx +121 -0
- package/docs-cache/social-plus-sdk/getting-started/platform-setup/mobile/ios-quick-start.mdx +225 -0
- package/docs-cache/social-plus-sdk/getting-started/platform-setup/web/web-quick-start.mdx +99 -0
- package/docs-cache/social-plus-sdk/social/communities-spaces/organization/community-invitation.mdx +459 -0
- package/docs-cache/social-plus-sdk/social/communities-spaces/organization/join-leave-community.mdx +449 -0
- package/docs-cache/social-plus-sdk/social/communities-spaces/organization/query-community-members.mdx +376 -0
- package/docs-cache/social-plus-sdk/social/content-management/posts/creation/text-post.mdx +318 -0
- package/docs-cache/social-plus-sdk/social/discovery-engagement/notifications/notification-tray-status.mdx +399 -0
- package/docs-cache/social-plus-sdk/social/user-relationship/blocking/block-unblock-user.mdx +166 -0
- package/docs-cache/social-plus-sdk/social/user-relationship/following/get-follower-following-list.mdx +339 -0
- package/package.json +10 -3
- package/scripts/dart-model-extractor/bin/extract_models.dart +169 -0
- package/scripts/dart-model-extractor/pubspec.lock +149 -0
- package/scripts/dart-model-extractor/pubspec.yaml +16 -0
- package/scripts/extract-sdk-models.mjs +353 -12
- package/scripts/import-sdk-surface.mjs +10 -19
- package/sdk-surface/manifest.json +15 -15
- package/sdk-surface/models.android.json +1 -1
- package/sdk-surface/models.flutter.json +465 -465
- package/sdk-surface/models.ios.json +188 -188
- package/sdk-surface/models.typescript.json +1 -1
- package/skills/social-plus-vise/SKILL.md +14 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
# iOS Push Notifications
|
|
2
|
+
|
|
3
|
+
> Complete guide to implementing Apple Push Notification service (APNs) with iOS social.plus SDK for real-time messaging and engagement
|
|
4
|
+
|
|
5
|
+
Integrate Apple Push Notifications into your iOS app to deliver instant updates about messages, mentions, and community activities, keeping users engaged even when your app isn't active.
|
|
6
|
+
|
|
7
|
+
Push notifications require proper APNs certificate setup and valid entitlements. Production certificates work with App Store and TestFlight builds only.
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
Before implementing push notifications, ensure you have:
|
|
12
|
+
|
|
13
|
+
Active Apple Developer Program membership
|
|
14
|
+
iOS project with proper Bundle ID configured
|
|
15
|
+
social.plus iOS SDK properly integrated
|
|
16
|
+
Push Notifications capability enabled in Xcode
|
|
17
|
+
|
|
18
|
+
## Step 1: Generate APNs Certificate
|
|
19
|
+
|
|
20
|
+
### Create Certificate in Apple Developer Console
|
|
21
|
+
|
|
22
|
+
1. **Navigate to Certificates**
|
|
23
|
+
- Go to [Apple Developer Console](https://developer.apple.com/)
|
|
24
|
+
- Select **Certificates, Identifiers & Profiles**
|
|
25
|
+
- Click on **Certificates** → **+** button
|
|
26
|
+
|
|
27
|
+
2. **Select Certificate Type**
|
|
28
|
+
- Choose **Apple Push Notification service SSL (Sandbox & Production)**
|
|
29
|
+
- This universal certificate works for both development and production
|
|
30
|
+
|
|
31
|
+
**Universal Certificate**: The Sandbox & Production certificate eliminates the need for separate development and production certificates, simplifying your workflow.
|
|
32
|
+
|
|
33
|
+
3. **Configure Certificate**
|
|
34
|
+
- Select your app's **Bundle ID** from the dropdown
|
|
35
|
+
- Follow Apple's certificate creation wizard
|
|
36
|
+
- Download the generated **.cer** file
|
|
37
|
+
|
|
38
|
+
### Convert Certificate to .p12 Format
|
|
39
|
+
|
|
40
|
+
1. **Install Certificate**
|
|
41
|
+
- Double-click the downloaded **.cer** file
|
|
42
|
+
- Keychain Access will open automatically
|
|
43
|
+
- The certificate will be installed in your **Login** keychain
|
|
44
|
+
|
|
45
|
+
2. **Export as .p12**
|
|
46
|
+
- In Keychain Access, navigate to **Login → My Certificates**
|
|
47
|
+
- Locate your **Apple Push Services** certificate
|
|
48
|
+
- Right-click and select **Export "Apple Push Services..."**
|
|
49
|
+
- Choose **.p12** format and set a secure password
|
|
50
|
+
- Save the file (you'll need both the file and password for console upload)
|
|
51
|
+
|
|
52
|
+
**Certificate Security**: Store your .p12 file and password securely. When you create a new certificate, the previous one is automatically revoked.
|
|
53
|
+
|
|
54
|
+
## Step 2: Upload to social.plus Console
|
|
55
|
+
|
|
56
|
+
1. **Access Console**
|
|
57
|
+
- Open your [social.plus Console](https://console.amity.co)
|
|
58
|
+
- Navigate to **Settings → Push Notifications**
|
|
59
|
+
|
|
60
|
+
2. **Upload Certificate**
|
|
61
|
+
- Click **Upload Certificate** in the iOS section
|
|
62
|
+
- Select your **.p12** file
|
|
63
|
+
- Enter the password you set during export
|
|
64
|
+
- Click **Save** to complete the setup
|
|
65
|
+
|
|
66
|
+
**Certificate Validation**: The console will validate your certificate upon upload. If there are issues, check that the Bundle ID matches your app configuration.
|
|
67
|
+
|
|
68
|
+
## Step 3: iOS App Configuration
|
|
69
|
+
|
|
70
|
+
### Enable Push Notifications Capability
|
|
71
|
+
|
|
72
|
+
In Xcode, enable the Push Notifications capability:
|
|
73
|
+
|
|
74
|
+
1. Select your app target
|
|
75
|
+
2. Go to **Signing & Capabilities**
|
|
76
|
+
3. Click **+ Capability**
|
|
77
|
+
4. Add **Push Notifications**
|
|
78
|
+
|
|
79
|
+
### Request Permission and Handle Registration
|
|
80
|
+
|
|
81
|
+
```swift
|
|
82
|
+
import UIKit
|
|
83
|
+
import UserNotifications
|
|
84
|
+
import AmitySDK
|
|
85
|
+
|
|
86
|
+
@main
|
|
87
|
+
class AppDelegate: UIResponder, UIApplicationDelegate {
|
|
88
|
+
|
|
89
|
+
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
|
90
|
+
|
|
91
|
+
// Configure notification center
|
|
92
|
+
UNUserNotificationCenter.current().delegate = self
|
|
93
|
+
|
|
94
|
+
// Request notification permissions
|
|
95
|
+
requestNotificationPermissions()
|
|
96
|
+
|
|
97
|
+
return true
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private func requestNotificationPermissions() {
|
|
101
|
+
UNUserNotificationCenter.current().requestAuthorization(
|
|
102
|
+
options: [.alert, .badge, .sound, .provisional]
|
|
103
|
+
) { granted, error in
|
|
104
|
+
if let error = error {
|
|
105
|
+
print("Push notification permission error: \(error.localizedDescription)")
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if granted {
|
|
110
|
+
print("Push notifications authorized")
|
|
111
|
+
DispatchQueue.main.async {
|
|
112
|
+
UIApplication.shared.registerForRemoteNotifications()
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
print("Push notifications denied")
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Handle Device Token Registration
|
|
123
|
+
|
|
124
|
+
```swift
|
|
125
|
+
extension AppDelegate {
|
|
126
|
+
|
|
127
|
+
func application(_ application: UIApplication,
|
|
128
|
+
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
|
|
129
|
+
|
|
130
|
+
// Convert token to string
|
|
131
|
+
let tokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
|
|
132
|
+
print("Device token: \(tokenString)")
|
|
133
|
+
|
|
134
|
+
// Register with social.plus SDK
|
|
135
|
+
registerDeviceWithAmitySDK(token: tokenString)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
func application(_ application: UIApplication,
|
|
139
|
+
didFailToRegisterForRemoteNotificationsWithError error: Error) {
|
|
140
|
+
print("Failed to register for remote notifications: \(error.localizedDescription)")
|
|
141
|
+
|
|
142
|
+
// Handle registration failure
|
|
143
|
+
handleRegistrationFailure(error: error)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private func registerDeviceWithAmitySDK(token: String) {
|
|
147
|
+
AmityManager.shared.client?.registerDevice(
|
|
148
|
+
withToken: token,
|
|
149
|
+
completion: { [weak self] success, error in
|
|
150
|
+
if success {
|
|
151
|
+
print("Successfully registered device with Amity SDK")
|
|
152
|
+
self?.onDeviceRegistrationSuccess(token: token)
|
|
153
|
+
} else {
|
|
154
|
+
print("Failed to register device: \(error?.localizedDescription ?? "Unknown error")")
|
|
155
|
+
self?.handleRegistrationFailure(error: error)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private func onDeviceRegistrationSuccess(token: String) {
|
|
162
|
+
// Store token locally for reference
|
|
163
|
+
UserDefaults.standard.set(token, forKey: "device_token")
|
|
164
|
+
|
|
165
|
+
// Update UI or perform additional setup
|
|
166
|
+
NotificationCenter.default.post(
|
|
167
|
+
name: .deviceTokenRegistered,
|
|
168
|
+
object: nil,
|
|
169
|
+
userInfo: ["token": token]
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private func handleRegistrationFailure(error: Error?) {
|
|
174
|
+
// Implement retry logic
|
|
175
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 30) {
|
|
176
|
+
UIApplication.shared.registerForRemoteNotifications()
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// MARK: - Notification Names
|
|
182
|
+
extension Notification.Name {
|
|
183
|
+
static let deviceTokenRegistered = Notification.Name("deviceTokenRegistered")
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Best Practices
|
|
188
|
+
|
|
189
|
+
**Strategic Permission Requests**: Don't ask for notification permissions immediately on app launch. Request them at meaningful moments.
|
|
190
|
+
|
|
191
|
+
```swift
|
|
192
|
+
// Good: Request after user joins a channel
|
|
193
|
+
func didJoinChannel() {
|
|
194
|
+
NotificationPermissionManager.shared.requestPermissionIfNeeded { granted in
|
|
195
|
+
if granted {
|
|
196
|
+
print("User enabled notifications for channel updates")
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Bad: Request immediately on app launch
|
|
202
|
+
func application(_ application: UIApplication, didFinishLaunchingWithOptions...) -> Bool {
|
|
203
|
+
// Don't do this immediately
|
|
204
|
+
// UNUserNotificationCenter.current().requestAuthorization(...)
|
|
205
|
+
return true
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Robust Token Management**: Implement comprehensive error handling for token registration failures.
|
|
210
|
+
|
|
211
|
+
```swift
|
|
212
|
+
class TokenRetryManager {
|
|
213
|
+
private var retryCount = 0
|
|
214
|
+
private let maxRetries = 3
|
|
215
|
+
private let retryDelay: TimeInterval = 30
|
|
216
|
+
|
|
217
|
+
func registerWithRetry(token: String) {
|
|
218
|
+
AmityManager.shared.client?.registerDevice(withToken: token) { [weak self] success, error in
|
|
219
|
+
if success {
|
|
220
|
+
self?.retryCount = 0
|
|
221
|
+
print("Token registered successfully")
|
|
222
|
+
} else if let self = self, self.retryCount < self.maxRetries {
|
|
223
|
+
self.retryCount += 1
|
|
224
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + self.retryDelay) {
|
|
225
|
+
self.registerWithRetry(token: token)
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
print("Failed to register token after \(self?.maxRetries ?? 0) attempts")
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**Notification State Tracking**: Keep track of notification-related state across app lifecycle.
|
|
236
|
+
|
|
237
|
+
```swift
|
|
238
|
+
class NotificationStateManager {
|
|
239
|
+
static let shared = NotificationStateManager()
|
|
240
|
+
|
|
241
|
+
private(set) var isRegistered = false
|
|
242
|
+
private(set) var deviceToken: String?
|
|
243
|
+
private(set) var authorizationStatus: UNAuthorizationStatus = .notDetermined
|
|
244
|
+
|
|
245
|
+
func updateRegistrationState(isRegistered: Bool, token: String?) {
|
|
246
|
+
self.isRegistered = isRegistered
|
|
247
|
+
self.deviceToken = token
|
|
248
|
+
|
|
249
|
+
// Notify observers
|
|
250
|
+
NotificationCenter.default.post(
|
|
251
|
+
name: .notificationStateChanged,
|
|
252
|
+
object: self
|
|
253
|
+
)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
func updateAuthorizationStatus(_ status: UNAuthorizationStatus) {
|
|
257
|
+
self.authorizationStatus = status
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
extension Notification.Name {
|
|
262
|
+
static let notificationStateChanged = Notification.Name("notificationStateChanged")
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**Comprehensive Testing**: Test push notifications across different scenarios and device states.
|
|
267
|
+
|
|
268
|
+
```swift
|
|
269
|
+
#if DEBUG
|
|
270
|
+
class NotificationTestingHelper {
|
|
271
|
+
static func logNotificationStatus() {
|
|
272
|
+
UNUserNotificationCenter.current().getNotificationSettings { settings in
|
|
273
|
+
print("Authorization Status: \(settings.authorizationStatus.rawValue)")
|
|
274
|
+
print("Alert Setting: \(settings.alertSetting.rawValue)")
|
|
275
|
+
print("Badge Setting: \(settings.badgeSetting.rawValue)")
|
|
276
|
+
print("Sound Setting: \(settings.soundSetting.rawValue)")
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
static func simulateNotification() {
|
|
281
|
+
let content = UNMutableNotificationContent()
|
|
282
|
+
content.title = "Test Notification"
|
|
283
|
+
content.body = "This is a test notification"
|
|
284
|
+
content.sound = .default
|
|
285
|
+
|
|
286
|
+
let request = UNNotificationRequest(
|
|
287
|
+
identifier: "test",
|
|
288
|
+
content: content,
|
|
289
|
+
trigger: UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
UNUserNotificationCenter.current().add(request)
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
#endif
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Testing & Debugging
|
|
299
|
+
|
|
300
|
+
### Debug Notification Status
|
|
301
|
+
|
|
302
|
+
```swift
|
|
303
|
+
class NotificationDebugger {
|
|
304
|
+
|
|
305
|
+
static func printDebugInfo() {
|
|
306
|
+
print("=== Notification Debug Info ===")
|
|
307
|
+
|
|
308
|
+
// Check authorization status
|
|
309
|
+
UNUserNotificationCenter.current().getNotificationSettings { settings in
|
|
310
|
+
print("Authorization Status: \(settings.authorizationStatus)")
|
|
311
|
+
print("Alert Setting: \(settings.alertSetting)")
|
|
312
|
+
print("Badge Setting: \(settings.badgeSetting)")
|
|
313
|
+
print("Sound Setting: \(settings.soundSetting)")
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Check device token
|
|
317
|
+
if let token = UserDefaults.standard.string(forKey: "device_token") {
|
|
318
|
+
print("Stored Device Token: \(token)")
|
|
319
|
+
} else {
|
|
320
|
+
print("No device token stored")
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Check badge count
|
|
324
|
+
print("Current Badge Count: \(UIApplication.shared.applicationIconBadgeNumber)")
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
static func testLocalNotification() {
|
|
328
|
+
let content = UNMutableNotificationContent()
|
|
329
|
+
content.title = "Test Notification"
|
|
330
|
+
content.body = "This is a test notification from your app"
|
|
331
|
+
content.sound = .default
|
|
332
|
+
content.badge = 1
|
|
333
|
+
|
|
334
|
+
let request = UNNotificationRequest(
|
|
335
|
+
identifier: UUID().uuidString,
|
|
336
|
+
content: content,
|
|
337
|
+
trigger: UNTimeIntervalNotificationTrigger(timeInterval: 2, repeats: false)
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
UNUserNotificationCenter.current().add(request) { error in
|
|
341
|
+
if let error = error {
|
|
342
|
+
print("Failed to schedule test notification: \(error)")
|
|
343
|
+
} else {
|
|
344
|
+
print("Test notification scheduled")
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## Troubleshooting
|
|
352
|
+
|
|
353
|
+
**Notifications Not Received**:
|
|
354
|
+
|
|
355
|
+
1. **Certificate Issues**: Verify .p12 certificate is valid and uploaded correctly
|
|
356
|
+
2. **Build Configuration**: Use TestFlight or App Store builds (not debug builds)
|
|
357
|
+
3. **Permissions**: Check notification permissions in iOS Settings
|
|
358
|
+
4. **Token Registration**: Ensure device token is successfully registered with social.plus SDK
|
|
359
|
+
5. **Bundle ID Mismatch**: Verify certificate Bundle ID matches your app
|
|
360
|
+
|
|
361
|
+
```swift
|
|
362
|
+
// Debug token registration
|
|
363
|
+
func debugTokenRegistration() {
|
|
364
|
+
print("App Bundle ID: \(Bundle.main.bundleIdentifier ?? "Unknown")")
|
|
365
|
+
|
|
366
|
+
if let token = UserDefaults.standard.string(forKey: "device_token") {
|
|
367
|
+
print("Current Token: \(token)")
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Re-register token
|
|
371
|
+
UIApplication.shared.registerForRemoteNotifications()
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
**Certificate Validation Issues**:
|
|
376
|
+
|
|
377
|
+
1. **Expired Certificate**: Check certificate expiration date
|
|
378
|
+
2. **Wrong Environment**: Ensure using Sandbox & Production certificate
|
|
379
|
+
3. **Password Incorrect**: Verify .p12 password in console
|
|
380
|
+
4. **Bundle ID Mismatch**: Certificate must match exact Bundle ID
|
|
381
|
+
|
|
382
|
+
```swift
|
|
383
|
+
// Validate certificate setup
|
|
384
|
+
func validateCertificateSetup() {
|
|
385
|
+
print("Bundle ID: \(Bundle.main.bundleIdentifier ?? "Not found")")
|
|
386
|
+
print("Push capability enabled: \(Bundle.main.object(forInfoDictionaryKey: "UIBackgroundModes") != nil)")
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**Platform-Specific Problems**:
|
|
391
|
+
|
|
392
|
+
1. **Simulator Limitations**: Push notifications don't work in iOS Simulator
|
|
393
|
+
2. **Debug Build Restrictions**: Debug builds can't receive production push notifications
|
|
394
|
+
3. **Background App Refresh**: Check if disabled in iOS Settings
|
|
395
|
+
4. **Do Not Disturb Mode**: May suppress notification display
|
|
396
|
+
|
|
397
|
+
```swift
|
|
398
|
+
// Check background refresh status
|
|
399
|
+
func checkBackgroundRefreshStatus() {
|
|
400
|
+
let status = UIApplication.shared.backgroundRefreshStatus
|
|
401
|
+
switch status {
|
|
402
|
+
case .available:
|
|
403
|
+
print("Background refresh available")
|
|
404
|
+
case .denied:
|
|
405
|
+
print("Background refresh denied")
|
|
406
|
+
case .restricted:
|
|
407
|
+
print("Background refresh restricted")
|
|
408
|
+
@unknown default:
|
|
409
|
+
print("Unknown background refresh status")
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
## Related Resources
|
|
415
|
+
|
|
416
|
+
Official Apple push notification documentation
|
|
417
|
+
UserNotifications framework reference
|
|
418
|
+
Apple Developer certificate portal
|
|
419
|
+
Test push notifications with TestFlight
|
|
420
|
+
|
|
421
|
+
**Production Requirements**: Push notifications only work with production builds distributed through App Store or TestFlight. Debug builds from Xcode cannot receive push notifications.
|
|
422
|
+
|
|
423
|
+
---
|