@react-native-kakao/share 3.1.0-next.0 → 3.1.0-next.2

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.
Files changed (32) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/RNCKakaoShare.podspec +0 -1
  3. package/android/build.gradle +1 -2
  4. package/android/src/main/java/net/mjstudio/rnkakao/share/RNCKakaoShareModule.kt +321 -12
  5. package/android/src/main/java/net/mjstudio/rnkakao/share/RNCKakaoShareTemplates.kt +5 -2
  6. package/ios/RNCKakaoShare.mm +64 -5
  7. package/ios/RNCKakaoShareManager.swift +315 -37
  8. package/lib/commonjs/index.js +140 -30
  9. package/lib/commonjs/index.js.map +1 -1
  10. package/lib/commonjs/index.web.js +199 -21
  11. package/lib/commonjs/index.web.js.map +1 -1
  12. package/lib/commonjs/spec/NativeKakaoShare.ts +77 -4
  13. package/lib/commonjs/validateSharePickerSettings.js +33 -0
  14. package/lib/commonjs/validateSharePickerSettings.js.map +1 -0
  15. package/lib/module/index.js +131 -30
  16. package/lib/module/index.js.map +1 -1
  17. package/lib/module/index.web.js +190 -21
  18. package/lib/module/index.web.js.map +1 -1
  19. package/lib/module/spec/NativeKakaoShare.ts +77 -4
  20. package/lib/module/validateSharePickerSettings.js +29 -0
  21. package/lib/module/validateSharePickerSettings.js.map +1 -0
  22. package/lib/typescript/src/index.d.ts +97 -37
  23. package/lib/typescript/src/index.d.ts.map +1 -1
  24. package/lib/typescript/src/spec/NativeKakaoShare.d.ts +72 -1
  25. package/lib/typescript/src/spec/NativeKakaoShare.d.ts.map +1 -1
  26. package/lib/typescript/src/validateSharePickerSettings.d.ts +6 -0
  27. package/lib/typescript/src/validateSharePickerSettings.d.ts.map +1 -0
  28. package/package.json +3 -3
  29. package/src/index.ts +278 -17
  30. package/src/index.web.ts +234 -38
  31. package/src/spec/NativeKakaoShare.ts +77 -4
  32. package/src/validateSharePickerSettings.ts +38 -0
@@ -6,10 +6,192 @@ import KakaoSDKTemplate
6
6
  import React
7
7
  import RNCKakaoCore
8
8
  import SafariServices
9
+ import UIKit
10
+
11
+ private let noCustomTemplateId: Int64 = -1
9
12
 
10
13
  @objc public class RNCKakaoShareManager: NSObject {
11
14
  @objc public static let shared = RNCKakaoShareManager()
12
15
 
16
+ @objc public func makeTemplateUrl(
17
+ _ templateType: String,
18
+ templateId: Int64,
19
+ templateJson: [String: Any],
20
+ templateArgs: [String: String]?,
21
+ serverCallbackArgs: [String: String]?,
22
+ resolve: @escaping RCTPromiseResolveBlock,
23
+ reject: @escaping RCTPromiseRejectBlock
24
+ ) {
25
+ onMain {
26
+ do {
27
+ let url: URL?
28
+ if templateType == "custom" {
29
+ url = ShareApi.shared.makeCustomUrl(
30
+ templateId: templateId, templateArgs: templateArgs,
31
+ serverCallbackArgs: serverCallbackArgs
32
+ )
33
+ } else if templateType == "scrap" {
34
+ guard let requestUrl = templateJson["requestUrl"] as? String else {
35
+ throw RNCKakaoError.unknown("requestUrl is required")
36
+ }
37
+ url = ShareApi.shared.makeScrapUrl(
38
+ requestUrl: requestUrl,
39
+ templateId: templateId == noCustomTemplateId ? nil : templateId,
40
+ templateArgs: templateArgs,
41
+ serverCallbackArgs: serverCallbackArgs
42
+ )
43
+ } else {
44
+ var template: [String: Any?] = templateJson
45
+ let templatable = try self.generateTemplatable(templateType, &template)
46
+ url = ShareApi.shared.makeDefaultUrl(
47
+ templatable: templatable, serverCallbackArgs: serverCallbackArgs
48
+ )
49
+ }
50
+ guard let url else {
51
+ throw RNCKakaoError.unknown("Failed to create sharing URL")
52
+ }
53
+ resolve(url.absoluteString)
54
+ } catch {
55
+ RNCKakaoUtil.reject(reject, error)
56
+ }
57
+ }
58
+ }
59
+
60
+ @objc public func isKakaoTalkSharingAvailable(_ resolve: @escaping RCTPromiseResolveBlock) {
61
+ onMain {
62
+ resolve(ShareApi.isKakaoTalkSharingAvailable())
63
+ }
64
+ }
65
+
66
+ @objc public func getTemplateDiagnostics(
67
+ _ templateType: String,
68
+ templateId: Int64,
69
+ templateJson: [String: Any],
70
+ templateArgs: [String: String]?,
71
+ serverCallbackArgs: [String: String]?,
72
+ pickerSettings: [String: Any]?,
73
+ resolve: @escaping RCTPromiseResolveBlock,
74
+ reject: @escaping RCTPromiseRejectBlock
75
+ ) {
76
+ onMain {
77
+ let requestUrl = templateType == "scrap" ? templateJson["requestUrl"] as? String : nil
78
+ guard templateType != "scrap" || requestUrl != nil else {
79
+ RNCKakaoUtil.reject(reject, RNCKakaoError.unknown("requestUrl is required"))
80
+ return
81
+ }
82
+ let customTemplateId: Int64? =
83
+ templateType == "custom" || templateId != noCustomTemplateId ? templateId : nil
84
+ self.runShare(
85
+ templateType: templateType,
86
+ templateId: customTemplateId,
87
+ defaultTemplate: templateJson,
88
+ useWebBrowserIfKakaoTalkNotAvailable: false,
89
+ templateArgs: templateArgs,
90
+ serverCallbackArgs: serverCallbackArgs,
91
+ pickerSettings: pickerSettings,
92
+ requestUrl: requestUrl,
93
+ resolve: resolve,
94
+ reject: reject,
95
+ diagnosticsOnly: true
96
+ )
97
+ }
98
+ }
99
+
100
+ @objc public func uploadImage(
101
+ _ imageUri: String,
102
+ secureResource: Bool,
103
+ resolve: @escaping RCTPromiseResolveBlock,
104
+ reject: @escaping RCTPromiseRejectBlock
105
+ ) {
106
+ DispatchQueue.global(qos: .userInitiated).async {
107
+ do {
108
+ let maxImageBytes = 5 * 1024 * 1024
109
+ let imageSizeError = "Image must be no larger than 5 MB"
110
+ let data: Data
111
+ if imageUri.hasPrefix("data:image/") {
112
+ let parts = imageUri.split(separator: ",", maxSplits: 1, omittingEmptySubsequences: false)
113
+ guard parts.count == 2, parts[0].hasSuffix(";base64") else {
114
+ throw RNCKakaoError.unknown("Expected a base64 image data URI")
115
+ }
116
+ guard parts[1].utf8.count <= ((maxImageBytes + 2) / 3) * 4 else {
117
+ throw RNCKakaoError.unknown(imageSizeError)
118
+ }
119
+ guard let decoded = Data(base64Encoded: String(parts[1])) else {
120
+ throw RNCKakaoError.unknown("Expected a base64 image data URI")
121
+ }
122
+ data = decoded
123
+ } else {
124
+ let url = imageUri.hasPrefix("/") ? URL(fileURLWithPath: imageUri) : URL(string: imageUri)
125
+ guard let url, url.isFileURL else {
126
+ throw RNCKakaoError.unknown("Expected a local file or base64 image data URI")
127
+ }
128
+ let file = try FileHandle(forReadingFrom: url)
129
+ defer { try? file.close() }
130
+ data = try file.read(upToCount: maxImageBytes + 1) ?? Data()
131
+ }
132
+ guard data.count <= maxImageBytes else {
133
+ throw RNCKakaoError.unknown(imageSizeError)
134
+ }
135
+ guard let image = UIImage(data: data) else {
136
+ throw RNCKakaoError.unknown("Image file cannot be decoded")
137
+ }
138
+ onMain {
139
+ ShareApi.shared
140
+ .imageUpload(image: image, secureResource: secureResource) { result, error in
141
+ if let error {
142
+ RNCKakaoUtil.reject(reject, error)
143
+ } else if let result {
144
+ let original = result.infos.original
145
+ resolve([
146
+ "infos": [
147
+ "original": [
148
+ "url": original.url.absoluteString,
149
+ "contentType": original.contentType,
150
+ "length": original.length,
151
+ "width": original.width,
152
+ "height": original.height
153
+ ]
154
+ ]
155
+ ])
156
+ } else {
157
+ RNCKakaoUtil.reject(
158
+ reject,
159
+ RNCKakaoError.responseNotFound(name: "imageUploadResult")
160
+ )
161
+ }
162
+ }
163
+ }
164
+ } catch {
165
+ RNCKakaoUtil.reject(reject, error)
166
+ }
167
+ }
168
+ }
169
+
170
+ @objc public func shareScrapTemplate(
171
+ _ requestUrl: String,
172
+ useWebBrowserIfKakaoTalkNotAvailable: Bool,
173
+ templateId: NSNumber?,
174
+ templateArgs: [String: String]?,
175
+ serverCallbackArgs: [String: String]?,
176
+ pickerSettings: [String: Any]?,
177
+ resolve: @escaping RCTPromiseResolveBlock,
178
+ reject: @escaping RCTPromiseRejectBlock
179
+ ) {
180
+ onMain {
181
+ self.runShare(
182
+ templateType: "scrap",
183
+ templateId: templateId?.int64Value,
184
+ useWebBrowserIfKakaoTalkNotAvailable: useWebBrowserIfKakaoTalkNotAvailable,
185
+ templateArgs: templateArgs,
186
+ serverCallbackArgs: serverCallbackArgs,
187
+ pickerSettings: pickerSettings,
188
+ requestUrl: requestUrl,
189
+ resolve: resolve,
190
+ reject: reject
191
+ )
192
+ }
193
+ }
194
+
13
195
  @objc public func scrapImage(
14
196
  _ imageUrl: String,
15
197
  secureResource: Bool,
@@ -53,6 +235,7 @@ import SafariServices
53
235
  useWebBrowserIfKakaoTalkNotAvailable: Bool,
54
236
  templateArgs: [String: String]?,
55
237
  serverCallbackArgs: [String: String]?,
238
+ pickerSettings: [String: Any]?,
56
239
  resolve: @escaping RCTPromiseResolveBlock,
57
240
  reject: @escaping RCTPromiseRejectBlock
58
241
  ) {
@@ -66,9 +249,44 @@ import SafariServices
66
249
  useWebBrowserIfKakaoTalkNotAvailable: useWebBrowserIfKakaoTalkNotAvailable,
67
250
  templateArgs: templateArgs,
68
251
  serverCallbackArgs: serverCallbackArgs,
252
+ pickerSettings: pickerSettings,
69
253
  resolve: resolve,
70
254
  reject: reject
71
255
  )
256
+ } else if templateType == "scrap" {
257
+ guard let requestUrl = templateJson["requestUrl"] as? String else {
258
+ RNCKakaoUtil.reject(
259
+ reject,
260
+ RNCKakaoError.unknown("requestUrl is required for scrap messages")
261
+ )
262
+ return
263
+ }
264
+ let customTemplateId: Int64? = templateId == noCustomTemplateId ? nil : templateId
265
+ if sendType == "send-me" {
266
+ self.runSendMe(
267
+ templateType: templateType,
268
+ templateId: customTemplateId,
269
+ templateArgs: templateArgs,
270
+ resolve: resolve,
271
+ reject: reject,
272
+ requestUrl: requestUrl
273
+ )
274
+ } else if sendType == "send-friend" {
275
+ self.runSendFriend(
276
+ templateType: templateType,
277
+ templateId: customTemplateId,
278
+ receiverUuids: receiverUuids,
279
+ templateArgs: templateArgs,
280
+ resolve: resolve,
281
+ reject: reject,
282
+ requestUrl: requestUrl
283
+ )
284
+ } else {
285
+ RNCKakaoUtil.reject(
286
+ reject,
287
+ RNCKakaoError.unknown("Unknown sendType for scrap messages: \(sendType)")
288
+ )
289
+ }
72
290
  } else {
73
291
  self.shareOrSendDefaultTemplate(
74
292
  sendType: sendType,
@@ -77,6 +295,7 @@ import SafariServices
77
295
  receiverUuids: receiverUuids,
78
296
  useWebBrowserIfKakaoTalkNotAvailable: useWebBrowserIfKakaoTalkNotAvailable,
79
297
  serverCallbackArgs: serverCallbackArgs,
298
+ pickerSettings: pickerSettings,
80
299
  resolve: resolve,
81
300
  reject: reject
82
301
  )
@@ -92,6 +311,7 @@ import SafariServices
92
311
  useWebBrowserIfKakaoTalkNotAvailable: Bool,
93
312
  templateArgs: [String: String]?,
94
313
  serverCallbackArgs: [String: String]?,
314
+ pickerSettings: [String: Any]?,
95
315
  resolve: @escaping RCTPromiseResolveBlock,
96
316
  reject: @escaping RCTPromiseRejectBlock
97
317
  ) {
@@ -102,6 +322,7 @@ import SafariServices
102
322
  useWebBrowserIfKakaoTalkNotAvailable: useWebBrowserIfKakaoTalkNotAvailable,
103
323
  templateArgs: templateArgs,
104
324
  serverCallbackArgs: serverCallbackArgs,
325
+ pickerSettings: pickerSettings,
105
326
  resolve: resolve,
106
327
  reject: reject
107
328
  )
@@ -134,6 +355,7 @@ import SafariServices
134
355
  receiverUuids: [String],
135
356
  useWebBrowserIfKakaoTalkNotAvailable: Bool,
136
357
  serverCallbackArgs: [String: String]?,
358
+ pickerSettings: [String: Any]?,
137
359
  resolve: @escaping RCTPromiseResolveBlock,
138
360
  reject: @escaping RCTPromiseRejectBlock
139
361
  ) {
@@ -144,6 +366,7 @@ import SafariServices
144
366
  useWebBrowserIfKakaoTalkNotAvailable: useWebBrowserIfKakaoTalkNotAvailable,
145
367
  templateArgs: serverCallbackArgs,
146
368
  serverCallbackArgs: serverCallbackArgs,
369
+ pickerSettings: pickerSettings,
147
370
  resolve: resolve,
148
371
  reject: reject
149
372
  )
@@ -168,17 +391,25 @@ import SafariServices
168
391
  defaultTemplate: [String: Any?]? = nil,
169
392
  templateArgs: [String: String]? = nil,
170
393
  resolve: @escaping RCTPromiseResolveBlock,
171
- reject: @escaping RCTPromiseRejectBlock
394
+ reject: @escaping RCTPromiseRejectBlock,
395
+ requestUrl: String? = nil
172
396
  ) {
173
397
  let sendCompletion = { (error: Error?) in
174
398
  if let error {
175
399
  RNCKakaoUtil.reject(reject, error)
176
400
  } else {
177
- resolve(42)
401
+ resolve(nil)
178
402
  }
179
403
  }
180
404
 
181
- if let templateId {
405
+ if let requestUrl {
406
+ TalkApi.shared.sendScrapMemo(
407
+ requestUrl: requestUrl,
408
+ templateId: templateId,
409
+ templateArgs: templateArgs,
410
+ completion: sendCompletion
411
+ )
412
+ } else if let templateId {
182
413
  TalkApi.shared.sendCustomMemo(
183
414
  templateId: templateId,
184
415
  templateArgs: templateArgs,
@@ -206,19 +437,37 @@ import SafariServices
206
437
  receiverUuids: [String],
207
438
  templateArgs: [String: String]? = nil,
208
439
  resolve: @escaping RCTPromiseResolveBlock,
209
- reject: @escaping RCTPromiseRejectBlock
440
+ reject: @escaping RCTPromiseRejectBlock,
441
+ requestUrl: String? = nil
210
442
  ) {
211
443
  let sendCompletion = { (messageSendResult: MessageSendResult?, error: Error?) in
212
444
  if let error {
213
445
  RNCKakaoUtil.reject(reject, error)
214
446
  } else if let messageSendResult {
215
- resolve(messageSendResult.successfulReceiverUuids ?? [])
447
+ resolve([
448
+ "successfulReceiverUuids": messageSendResult.successfulReceiverUuids ?? [],
449
+ "failureInfos": messageSendResult.failureInfos?.map { failure in
450
+ [
451
+ "code": failure.code,
452
+ "msg": failure.msg,
453
+ "receiverUuids": failure.receiverUuids
454
+ ]
455
+ } ?? []
456
+ ])
216
457
  } else {
217
458
  RNCKakaoUtil.reject(reject, RNCKakaoError.unknown("messageSendResult"))
218
459
  }
219
460
  }
220
461
 
221
- if let templateId {
462
+ if let requestUrl {
463
+ TalkApi.shared.sendScrapMessage(
464
+ requestUrl: requestUrl,
465
+ templateId: templateId,
466
+ templateArgs: templateArgs,
467
+ receiverUuids: receiverUuids,
468
+ completion: sendCompletion
469
+ )
470
+ } else if let templateId {
222
471
  TalkApi.shared.sendCustomMessage(
223
472
  templateId: templateId,
224
473
  templateArgs: templateArgs,
@@ -251,16 +500,26 @@ import SafariServices
251
500
  useWebBrowserIfKakaoTalkNotAvailable: Bool,
252
501
  templateArgs: [String: String]? = nil,
253
502
  serverCallbackArgs: [String: String]?,
503
+ pickerSettings: [String: Any]?,
504
+ requestUrl: String? = nil,
254
505
  resolve: @escaping RCTPromiseResolveBlock,
255
- reject: @escaping RCTPromiseRejectBlock
506
+ reject: @escaping RCTPromiseRejectBlock,
507
+ diagnosticsOnly: Bool = false
256
508
  ) {
257
509
  let shareCompletion = { (sharingResult: SharingResult?, error: Error?) in
258
510
  if let error {
259
511
  RNCKakaoUtil.reject(reject, error)
260
512
  } else if let sharingResult {
513
+ if diagnosticsOnly {
514
+ resolve([
515
+ "warningMsg": sharingResult.warningMsg ?? [:],
516
+ "argumentMsg": sharingResult.argumentMsg ?? [:]
517
+ ])
518
+ return
519
+ }
261
520
  UIApplication.shared.open(sharingResult.url, options: [:]) { success in
262
521
  if success {
263
- resolve(42)
522
+ resolve(nil)
264
523
  } else {
265
524
  RNCKakaoUtil.reject(
266
525
  reject,
@@ -273,10 +532,24 @@ import SafariServices
273
532
  }
274
533
  }
275
534
 
276
- if ShareApi.isKakaoTalkSharingAvailable() {
277
- if let templateId {
535
+ if diagnosticsOnly || ShareApi.isKakaoTalkSharingAvailable() {
536
+ let shareType = (pickerSettings?["type"] as? String).flatMap(ShareType.init(rawValue:))
537
+ let limit = (pickerSettings?["limit"] as? NSNumber)?.intValue
538
+ if let requestUrl {
539
+ ShareApi.shared.shareScrap(
540
+ requestUrl: requestUrl,
541
+ templateId: templateId,
542
+ templateArgs: templateArgs,
543
+ shareType: shareType,
544
+ limit: limit,
545
+ serverCallbackArgs: serverCallbackArgs,
546
+ completion: shareCompletion
547
+ )
548
+ } else if let templateId {
278
549
  ShareApi.shared.shareCustom(
279
550
  templateId: templateId,
551
+ shareType: shareType,
552
+ limit: limit,
280
553
  templateArgs: templateArgs,
281
554
  serverCallbackArgs: serverCallbackArgs,
282
555
  completion: shareCompletion
@@ -286,6 +559,8 @@ import SafariServices
286
559
  let templatable = try generateTemplatable(templateType, &defaultTemplate)
287
560
  ShareApi.shared.shareDefault(
288
561
  templatable: templatable,
562
+ shareType: shareType,
563
+ limit: limit,
289
564
  serverCallbackArgs: serverCallbackArgs,
290
565
  completion: shareCompletion
291
566
  )
@@ -299,25 +574,24 @@ import SafariServices
299
574
  )
300
575
  }
301
576
  } else if useWebBrowserIfKakaoTalkNotAvailable {
302
- if let templateId {
577
+ if let requestUrl {
578
+ if let url = ShareApi.shared.makeScrapUrl(
579
+ requestUrl: requestUrl,
580
+ templateId: templateId,
581
+ templateArgs: templateArgs,
582
+ serverCallbackArgs: serverCallbackArgs
583
+ ) {
584
+ presentShareUrl(url)
585
+ } else {
586
+ RNCKakaoUtil.reject(reject, RNCKakaoError.unknown("makeScrapUrl failed"))
587
+ }
588
+ } else if let templateId {
303
589
  if let url = ShareApi.shared.makeCustomUrl(
304
590
  templateId: templateId,
305
591
  templateArgs: templateArgs,
306
592
  serverCallbackArgs: serverCallbackArgs
307
593
  ) {
308
- let safariViewController = SFSafariViewController(url: url)
309
- safariViewController.modalTransitionStyle = .crossDissolve
310
- safariViewController.modalPresentationStyle = .overCurrentContext
311
- RNCKakaoUtil.presentViewController(safariViewController) { success in
312
- if success {
313
- resolve(42)
314
- } else {
315
- RNCKakaoUtil.reject(
316
- reject,
317
- RNCKakaoError.unknown("SFSafariViewController open failed")
318
- )
319
- }
320
- }
594
+ presentShareUrl(url)
321
595
  } else {
322
596
  RNCKakaoUtil.reject(reject, RNCKakaoError.unknown("makeCustomUrl failed"))
323
597
  }
@@ -329,19 +603,7 @@ import SafariServices
329
603
  templatable: templatable,
330
604
  serverCallbackArgs: serverCallbackArgs
331
605
  ) {
332
- let safariViewController = SFSafariViewController(url: url)
333
- safariViewController.modalTransitionStyle = .crossDissolve
334
- safariViewController.modalPresentationStyle = .overCurrentContext
335
- RNCKakaoUtil.presentViewController(safariViewController) { success in
336
- if success {
337
- resolve(42)
338
- } else {
339
- RNCKakaoUtil.reject(
340
- reject,
341
- RNCKakaoError.unknown("SFSafariViewController open failed")
342
- )
343
- }
344
- }
606
+ presentShareUrl(url)
345
607
  } else {
346
608
  RNCKakaoUtil.reject(reject, RNCKakaoError.unknown("makeDefaultUrl failed"))
347
609
  }
@@ -357,6 +619,22 @@ import SafariServices
357
619
  } else {
358
620
  RNCKakaoUtil.reject(reject, RNCKakaoError.kakaoAppNotAvailable(app: .talk))
359
621
  }
622
+
623
+ func presentShareUrl(_ url: URL) {
624
+ let safariViewController = SFSafariViewController(url: url)
625
+ safariViewController.modalTransitionStyle = .crossDissolve
626
+ safariViewController.modalPresentationStyle = .overCurrentContext
627
+ RNCKakaoUtil.presentViewController(safariViewController) { success in
628
+ if success {
629
+ resolve(nil)
630
+ } else {
631
+ RNCKakaoUtil.reject(
632
+ reject,
633
+ RNCKakaoError.unknown("SFSafariViewController open failed")
634
+ )
635
+ }
636
+ }
637
+ }
360
638
  }
361
639
 
362
640
  private func generateTemplatable(