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

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 +26 -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 +323 -11
  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 -36
  8. package/lib/commonjs/index.js +137 -29
  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 +76 -3
  13. package/lib/commonjs/validateSharePickerSettings.js +33 -0
  14. package/lib/commonjs/validateSharePickerSettings.js.map +1 -0
  15. package/lib/module/index.js +128 -29
  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 +76 -3
  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 +83 -23
  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 +258 -15
  30. package/src/index.web.ts +232 -36
  31. package/src/spec/NativeKakaoShare.ts +76 -3
  32. package/src/validateSharePickerSettings.ts +38 -0
package/CHANGELOG.md CHANGED
@@ -3,6 +3,32 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## 3.1.0-next.1
7
+
8
+ ### Minor Changes
9
+
10
+ - d117308: Add local image uploads on Android, iOS, and web with image metadata and secure URL options.
11
+ - 483fd00: Add URL scrap messages to My Chatroom and friends on Android, iOS, and web.
12
+ - bf027c0: Add URL-scraped message sharing with custom template arguments and native browser fallback on Android, iOS, and web.
13
+ - ff35f20: Expose native URL builders for default, custom, and scraped-page sharing without launching a sharing interface. Report unsupported URL building explicitly on web.
14
+
15
+ Encode Android template execution-parameter keys and values before the SDK serializes them, preserving special characters across sharing URLs, sharing, and message sending.
16
+ - 1efca29: Expose Kakao Talk sharing availability and Kakao Navi installation checks on Android and iOS, with explicit false results on web.
17
+ - ceafbcf: Add optional friend message results with successful recipients and failure details on Android, iOS, and web.
18
+ - 314d493: Expose validated share target picker settings across native and web share templates.
19
+ - 18df9b3: Expose native sharing template warnings and argument diagnostics without opening a sharing interface. Normalize missing diagnostic maps to empty objects and reject the unsupported API explicitly on web.
20
+
21
+ ### Patch Changes
22
+
23
+ - 61c270a: Remove unused React Native module dependencies so Channel, Social, and Share can each be installed with Core alone. Declare Share's Android Talk SDK dependency directly.
24
+ - Updated dependencies [d5c5fb8]
25
+ - Updated dependencies [3027207]
26
+ - Updated dependencies [dfd32ca]
27
+ - Updated dependencies [2b223bf]
28
+ - Updated dependencies [67cd4e2]
29
+ - Updated dependencies [d81f9b7]
30
+ - @react-native-kakao/core@3.1.0-next.1
31
+
6
32
  ## 3.1.0-next.0
7
33
 
8
34
  ### Minor Changes
@@ -28,7 +28,6 @@ Pod::Spec.new do |s|
28
28
  end
29
29
 
30
30
  s.dependency 'RNCKakaoCore'
31
- s.dependency 'RNCKakaoSocial'
32
31
 
33
32
  # Kakao dependencies
34
33
  RNCKakaoSPM.dependency(s, sdk_version, %w[KakaoSDKCommon KakaoSDKAuth KakaoSDKUser KakaoSDKTemplate KakaoSDKTalk KakaoSDKShare])
@@ -1,7 +1,6 @@
1
1
  apply from: file('./../../core/android/package-json.gradle')
2
2
  def Versions = project.ext.RNCKakaoSdkVersions
3
3
  Project coreProject = project.ext.getWorkspaceProject("core")
4
- Project socialProject = project.ext.getWorkspaceProject("social")
5
4
 
6
5
  project.ext.applyPlugins()
7
6
 
@@ -40,6 +39,6 @@ dependencies {
40
39
  implementation "com.facebook.react:react-android"
41
40
 
42
41
  api coreProject
43
- api socialProject
44
42
  implementation "com.kakao.sdk:v2-share:${Versions.share}"
43
+ implementation "com.kakao.sdk:v2-talk:${Versions.talk}"
45
44
  }
@@ -1,6 +1,8 @@
1
1
  package net.mjstudio.rnkakao.share
2
2
 
3
3
  import android.content.ActivityNotFoundException
4
+ import android.net.Uri
5
+ import android.util.Base64
4
6
  import com.facebook.react.bridge.Promise
5
7
  import com.facebook.react.bridge.ReactApplicationContext
6
8
  import com.facebook.react.bridge.ReactMethod
@@ -9,6 +11,7 @@ import com.facebook.react.bridge.ReadableMap
9
11
  import com.kakao.sdk.common.util.KakaoCustomTabsClient
10
12
  import com.kakao.sdk.share.ShareClient
11
13
  import com.kakao.sdk.share.WebSharerClient
14
+ import com.kakao.sdk.share.model.ShareType
12
15
  import com.kakao.sdk.share.model.SharingResult
13
16
  import com.kakao.sdk.talk.TalkApiClient
14
17
  import com.kakao.sdk.talk.model.MessageSendResult
@@ -23,10 +26,221 @@ import net.mjstudio.rnkakao.core.util.onMain
23
26
  import net.mjstudio.rnkakao.core.util.pushStringList
24
27
  import net.mjstudio.rnkakao.core.util.rejectWith
25
28
  import net.mjstudio.rnkakao.core.util.toStringMap
29
+ import java.io.File
30
+ import kotlin.concurrent.thread
31
+
32
+ private const val NO_CUSTOM_TEMPLATE_ID = -1.0
26
33
 
27
34
  class RNCKakaoShareModule internal constructor(
28
35
  context: ReactApplicationContext,
29
36
  ) : NativeKakaoShareSpec(context) {
37
+ @ReactMethod
38
+ override fun isKakaoTalkSharingAvailable(promise: Promise) =
39
+ onMain {
40
+ promise.resolve(ShareClient.instance.isKakaoTalkSharingAvailable(reactApplicationContext))
41
+ }
42
+
43
+ @ReactMethod
44
+ override fun makeTemplateUrl(
45
+ templateType: String,
46
+ templateId: Double,
47
+ templateJson: ReadableMap,
48
+ templateArgs: ReadableMap,
49
+ serverCallbackArgs: ReadableMap,
50
+ promise: Promise,
51
+ ) = onMain {
52
+ runCatching {
53
+ val args = templateArgs.toStringMap()
54
+ val callbacks = serverCallbackArgs.toStringMap()
55
+ val url =
56
+ when (templateType) {
57
+ "custom" -> {
58
+ WebSharerClient.instance.makeCustomUrl(templateId.toLong(), args, callbacks)
59
+ }
60
+
61
+ "scrap" -> {
62
+ WebSharerClient.instance.makeScrapUrl(
63
+ requireNotNull(templateJson.getString("requestUrl")) { "requestUrl is required" },
64
+ templateId.takeUnless { it == NO_CUSTOM_TEMPLATE_ID }?.toLong(),
65
+ args,
66
+ callbacks,
67
+ )
68
+ }
69
+
70
+ else -> {
71
+ WebSharerClient.instance.makeDefaultUrl(
72
+ RNCKakaoShareTemplates.createDefaultTemplate(templateJson, templateType),
73
+ callbacks,
74
+ )
75
+ }
76
+ }
77
+ url.toString()
78
+ }.onSuccess { promise.resolve(it) }.onFailure { promise.rejectWith(it) }
79
+ }
80
+
81
+ @ReactMethod
82
+ override fun getTemplateDiagnostics(
83
+ templateType: String,
84
+ templateId: Double,
85
+ templateJson: ReadableMap,
86
+ templateArgs: ReadableMap,
87
+ serverCallbackArgs: ReadableMap,
88
+ pickerSettings: ReadableMap?,
89
+ promise: Promise,
90
+ ) = onMain {
91
+ runCatching {
92
+ val requestUrl =
93
+ if (templateType == "scrap") {
94
+ requireNotNull(templateJson.getString("requestUrl")) { "requestUrl is required" }
95
+ } else {
96
+ null
97
+ }
98
+ runShare(
99
+ templateType = templateType,
100
+ templateId = templateId.takeUnless { templateType != "custom" && it == NO_CUSTOM_TEMPLATE_ID },
101
+ defaultTemplate = templateJson,
102
+ useWebBrowserIfKakaoTalkNotAvailable = false,
103
+ templateArgs = templateArgs,
104
+ serverCallbackArgs = serverCallbackArgs,
105
+ pickerSettings = pickerSettings,
106
+ promise = promise,
107
+ requestUrl = requestUrl,
108
+ diagnosticsOnly = true,
109
+ )
110
+ }.onFailure { promise.rejectWith(it) }
111
+ }
112
+
113
+ @ReactMethod
114
+ override fun uploadImage(
115
+ imageUri: String,
116
+ secureResource: Boolean,
117
+ promise: Promise,
118
+ ) {
119
+ thread {
120
+ var temporaryFile: File? = null
121
+ try {
122
+ val maxImageBytes = 5 * 1024 * 1024
123
+ val imageSizeError = "Image must be no larger than 5 MB"
124
+
125
+ fun createTemporaryImageFile(): File =
126
+ File.createTempFile("kakao-share-image-", ".tmp", reactApplicationContext.cacheDir).also {
127
+ temporaryFile = it
128
+ }
129
+ val uri = Uri.parse(imageUri)
130
+ val file =
131
+ when (uri.scheme) {
132
+ null -> {
133
+ File(imageUri)
134
+ }
135
+
136
+ "file" -> {
137
+ File(requireNotNull(uri.path))
138
+ }
139
+
140
+ "content" -> {
141
+ val copiedFile = createTemporaryImageFile()
142
+ requireNotNull(reactApplicationContext.contentResolver.openInputStream(uri)).use { input ->
143
+ copiedFile.outputStream().use { output ->
144
+ val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
145
+ var total = 0
146
+ var count = input.read(buffer)
147
+ while (count != -1) {
148
+ total += count
149
+ require(total <= maxImageBytes) { imageSizeError }
150
+ output.write(buffer, 0, count)
151
+ count = input.read(buffer)
152
+ }
153
+ }
154
+ }
155
+ copiedFile
156
+ }
157
+
158
+ "data" -> {
159
+ require(imageUri.startsWith("data:image/") && imageUri.substringBefore(',').endsWith(";base64")) {
160
+ "Expected a base64 image data URI"
161
+ }
162
+ val maxEncodedImageLength = ((maxImageBytes + 2) / 3) * 4
163
+ val encodedImage =
164
+ buildString {
165
+ for (index in imageUri.indexOf(',') + 1 until imageUri.length) {
166
+ val character = imageUri[index]
167
+ if (!character.isWhitespace()) {
168
+ require(length < maxEncodedImageLength) { imageSizeError }
169
+ append(character)
170
+ }
171
+ }
172
+ }
173
+ val bytes = Base64.decode(encodedImage, Base64.DEFAULT)
174
+ require(bytes.size <= maxImageBytes) { imageSizeError }
175
+ val decodedFile = createTemporaryImageFile()
176
+ decodedFile.writeBytes(bytes)
177
+ decodedFile
178
+ }
179
+
180
+ else -> {
181
+ throw IllegalArgumentException("Expected a local file, content, or base64 image data URI")
182
+ }
183
+ }
184
+ require(file.isFile && file.canRead()) { "Image file cannot be read" }
185
+ require(file.length() <= maxImageBytes) { imageSizeError }
186
+ ShareClient.instance.uploadImage(file, secureResource) { result, error ->
187
+ temporaryFile?.delete()
188
+ if (error != null) {
189
+ promise.rejectWith(error)
190
+ } else if (result != null) {
191
+ val original = result.infos.original
192
+ promise.resolve(
193
+ argMap().apply {
194
+ putMap(
195
+ "infos",
196
+ argMap().apply {
197
+ putMap(
198
+ "original",
199
+ argMap().apply {
200
+ putString("url", original.url)
201
+ putString("contentType", original.contentType)
202
+ putDouble("length", original.length.toDouble())
203
+ putDouble("width", original.width.toDouble())
204
+ putDouble("height", original.height.toDouble())
205
+ },
206
+ )
207
+ },
208
+ )
209
+ },
210
+ )
211
+ } else {
212
+ promise.rejectWith(RNCKakaoResponseNotFoundException("imageUploadResult"))
213
+ }
214
+ }
215
+ } catch (error: Exception) {
216
+ temporaryFile?.delete()
217
+ promise.rejectWith(error)
218
+ }
219
+ }
220
+ }
221
+
222
+ @ReactMethod
223
+ override fun shareScrapTemplate(
224
+ requestUrl: String,
225
+ useWebBrowserIfKakaoTalkNotAvailable: Boolean,
226
+ templateId: Double?,
227
+ templateArgs: ReadableMap?,
228
+ serverCallbackArgs: ReadableMap?,
229
+ pickerSettings: ReadableMap?,
230
+ promise: Promise,
231
+ ) = onMain {
232
+ runShare(
233
+ templateType = "scrap",
234
+ templateId = templateId,
235
+ useWebBrowserIfKakaoTalkNotAvailable = useWebBrowserIfKakaoTalkNotAvailable,
236
+ templateArgs = templateArgs,
237
+ serverCallbackArgs = serverCallbackArgs,
238
+ pickerSettings = pickerSettings,
239
+ requestUrl = requestUrl,
240
+ promise = promise,
241
+ )
242
+ }
243
+
30
244
  @ReactMethod
31
245
  override fun scrapImage(
32
246
  imageUrl: String,
@@ -73,6 +287,7 @@ class RNCKakaoShareModule internal constructor(
73
287
  useWebBrowserIfKakaoTalkNotAvailable: Boolean,
74
288
  templateArgs: ReadableMap,
75
289
  serverCallbackArgs: ReadableMap,
290
+ pickerSettings: ReadableMap?,
76
291
  promise: Promise,
77
292
  ) = onMain {
78
293
  if (templateType == "custom") {
@@ -84,8 +299,36 @@ class RNCKakaoShareModule internal constructor(
84
299
  useWebBrowserIfKakaoTalkNotAvailable,
85
300
  templateArgs,
86
301
  serverCallbackArgs,
302
+ pickerSettings,
87
303
  promise,
88
304
  )
305
+ } else if (templateType == "scrap") {
306
+ val requestUrl = templateJson.toHashMap()["requestUrl"] as? String
307
+ if (requestUrl == null) {
308
+ promise.rejectWith(RNCKakaoUnknownException("requestUrl is required for scrap messages"))
309
+ return@onMain
310
+ }
311
+ val customTemplateId = templateId.takeUnless { it == NO_CUSTOM_TEMPLATE_ID }
312
+ when (sendType) {
313
+ "send-me" -> {
314
+ runSendToMe(templateType, customTemplateId, templateArgs = templateArgs, promise = promise, requestUrl = requestUrl)
315
+ }
316
+
317
+ "send-friend" -> {
318
+ runSendToFriends(
319
+ templateType,
320
+ receiverUuids.filterIsInstance<String>(),
321
+ customTemplateId,
322
+ templateArgs = templateArgs,
323
+ promise = promise,
324
+ requestUrl = requestUrl,
325
+ )
326
+ }
327
+
328
+ else -> {
329
+ promise.rejectWith(RNCKakaoUnknownException("Unknown sendType for scrap messages: $sendType"))
330
+ }
331
+ }
89
332
  } else {
90
333
  shareOrSendDefaultTemplate(
91
334
  sendType,
@@ -94,6 +337,7 @@ class RNCKakaoShareModule internal constructor(
94
337
  receiverUuids = receiverUuids.filterIsInstance<String>(),
95
338
  useWebBrowserIfKakaoTalkNotAvailable,
96
339
  serverCallbackArgs,
340
+ pickerSettings,
97
341
  promise,
98
342
  )
99
343
  }
@@ -107,6 +351,7 @@ class RNCKakaoShareModule internal constructor(
107
351
  useWebBrowserIfKakaoTalkNotAvailable: Boolean,
108
352
  templateArgs: ReadableMap?,
109
353
  serverCallbackArgs: ReadableMap?,
354
+ pickerSettings: ReadableMap?,
110
355
  promise: Promise,
111
356
  ) = when (sendType) {
112
357
  "share" -> {
@@ -117,6 +362,7 @@ class RNCKakaoShareModule internal constructor(
117
362
  useWebBrowserIfKakaoTalkNotAvailable,
118
363
  templateArgs,
119
364
  serverCallbackArgs,
365
+ pickerSettings,
120
366
  promise,
121
367
  )
122
368
  }
@@ -141,6 +387,7 @@ class RNCKakaoShareModule internal constructor(
141
387
  receiverUuids: List<String>,
142
388
  useWebBrowserIfKakaoTalkNotAvailable: Boolean,
143
389
  serverCallbackArgs: ReadableMap?,
390
+ pickerSettings: ReadableMap?,
144
391
  promise: Promise,
145
392
  ) = when (sendType) {
146
393
  "share" -> {
@@ -151,6 +398,7 @@ class RNCKakaoShareModule internal constructor(
151
398
  useWebBrowserIfKakaoTalkNotAvailable,
152
399
  argMap(),
153
400
  serverCallbackArgs,
401
+ pickerSettings,
154
402
  promise,
155
403
  )
156
404
  }
@@ -174,6 +422,7 @@ class RNCKakaoShareModule internal constructor(
174
422
  defaultTemplate: ReadableMap? = null,
175
423
  templateArgs: ReadableMap? = null,
176
424
  promise: Promise,
425
+ requestUrl: String? = null,
177
426
  ) {
178
427
  val callback = { e: Throwable? ->
179
428
  if (e != null) {
@@ -182,7 +431,9 @@ class RNCKakaoShareModule internal constructor(
182
431
  promise.resolve(42)
183
432
  }
184
433
  }
185
- if (templateId != null) {
434
+ if (requestUrl != null) {
435
+ TalkApiClient.instance.sendScrapMemo(requestUrl, templateId?.toLong(), templateArgs?.toStringMap(), callback)
436
+ } else if (templateId != null) {
186
437
  TalkApiClient.instance.sendCustomMemo(templateId.toLong(), templateArgs?.toStringMap(), callback)
187
438
  } else if (defaultTemplate != null) {
188
439
  runCatching {
@@ -203,6 +454,7 @@ class RNCKakaoShareModule internal constructor(
203
454
  defaultTemplate: ReadableMap? = null,
204
455
  templateArgs: ReadableMap? = null,
205
456
  promise: Promise,
457
+ requestUrl: String? = null,
206
458
  ) {
207
459
  val callback = { messageSendResult: MessageSendResult?, e: Throwable? ->
208
460
  if (e != null) {
@@ -210,10 +462,30 @@ class RNCKakaoShareModule internal constructor(
210
462
  } else if (messageSendResult == null) {
211
463
  promise.rejectWith(RNCKakaoResponseNotFoundException("messageSendResult"))
212
464
  } else {
213
- promise.resolve(argArr().pushStringList(messageSendResult.successfulReceiverUuids ?: listOf()))
465
+ promise.resolve(
466
+ argMap().apply {
467
+ putArray("successfulReceiverUuids", argArr().pushStringList(messageSendResult.successfulReceiverUuids ?: listOf()))
468
+ putArray(
469
+ "failureInfos",
470
+ argArr().apply {
471
+ messageSendResult.failureInfos?.forEach { failure ->
472
+ pushMap(
473
+ argMap().apply {
474
+ putInt("code", failure.code)
475
+ putString("msg", failure.msg)
476
+ putArray("receiverUuids", argArr().pushStringList(failure.receiverUuids))
477
+ },
478
+ )
479
+ }
480
+ },
481
+ )
482
+ },
483
+ )
214
484
  }
215
485
  }
216
- if (templateId != null) {
486
+ if (requestUrl != null) {
487
+ TalkApiClient.instance.sendScrapMessage(receiverUuids, requestUrl, templateId?.toLong(), templateArgs?.toStringMap(), callback)
488
+ } else if (templateId != null) {
217
489
  TalkApiClient.instance.sendCustomMessage(receiverUuids, templateId.toLong(), templateArgs?.toStringMap(), callback)
218
490
  } else if (defaultTemplate != null) {
219
491
  runCatching {
@@ -235,32 +507,63 @@ class RNCKakaoShareModule internal constructor(
235
507
  useWebBrowserIfKakaoTalkNotAvailable: Boolean,
236
508
  templateArgs: ReadableMap? = null,
237
509
  serverCallbackArgs: ReadableMap? = null,
510
+ pickerSettings: ReadableMap?,
238
511
  promise: Promise,
512
+ requestUrl: String? = null,
513
+ diagnosticsOnly: Boolean = false,
239
514
  ) {
240
- val context = reactApplicationContext.currentActivity
515
+ val context = if (diagnosticsOnly) reactApplicationContext else reactApplicationContext.currentActivity
241
516
  if (context == null) {
242
517
  promise.rejectWith(ActivityNotFoundException())
243
518
  return
244
519
  }
245
520
 
521
+ val result = if (requestUrl != null) null else 42
246
522
  val callback = { sharingResult: SharingResult?, error: Throwable? ->
247
523
  if (error != null) {
248
524
  promise.rejectWith(error)
249
525
  } else if (sharingResult != null) {
250
- context.startActivity(sharingResult.intent)
251
- promise.resolve(42)
526
+ if (diagnosticsOnly) {
527
+ promise.resolve(
528
+ argMap().apply {
529
+ putMap("warningMsg", argMap().apply { sharingResult.warningMsg.forEach { (key, value) -> putString(key, value) } })
530
+ putMap("argumentMsg", argMap().apply { sharingResult.argumentMsg.forEach { (key, value) -> putString(key, value) } })
531
+ },
532
+ )
533
+ } else {
534
+ context.startActivity(sharingResult.intent)
535
+ promise.resolve(result)
536
+ }
537
+ } else if (diagnosticsOnly || requestUrl != null) {
538
+ promise.rejectWith(RNCKakaoResponseNotFoundException("sharingResult"))
252
539
  } else {
253
- promise.resolve(42)
540
+ promise.resolve(result)
254
541
  }
255
542
  }
256
543
 
257
544
  if (ShareClient.instance.isKakaoTalkSharingAvailable(context)) {
258
- if (templateId != null) {
545
+ val pickerType = pickerSettings?.takeIf { it.hasKey("type") }?.getString("type")
546
+ val shareType = ShareType.entries.firstOrNull { it.value == pickerType }
547
+ val limit = pickerSettings?.takeIf { it.hasKey("limit") }?.getDouble("limit")?.toInt()
548
+ if (requestUrl != null) {
549
+ ShareClient.instance.shareScrap(
550
+ context,
551
+ requestUrl,
552
+ templateId = templateId?.toLong(),
553
+ templateArgs = templateArgs?.toStringMap(),
554
+ serverCallbackArgs = serverCallbackArgs?.toStringMap(),
555
+ shareType = shareType,
556
+ limit = limit,
557
+ callback = callback,
558
+ )
559
+ } else if (templateId != null) {
259
560
  ShareClient.instance.shareCustom(
260
561
  context,
261
562
  templateId.toLong(),
262
563
  templateArgs = templateArgs?.toStringMap(),
263
564
  serverCallbackArgs = serverCallbackArgs?.toStringMap(),
565
+ shareType = shareType,
566
+ limit = limit,
264
567
  callback = callback,
265
568
  )
266
569
  } else if (defaultTemplate != null) {
@@ -269,6 +572,8 @@ class RNCKakaoShareModule internal constructor(
269
572
  context,
270
573
  RNCKakaoShareTemplates.createDefaultTemplate(defaultTemplate, templateType),
271
574
  serverCallbackArgs = serverCallbackArgs?.toStringMap(),
575
+ shareType = shareType,
576
+ limit = limit,
272
577
  callback = callback,
273
578
  )
274
579
  }.onFailure {
@@ -278,7 +583,14 @@ class RNCKakaoShareModule internal constructor(
278
583
  } else if (useWebBrowserIfKakaoTalkNotAvailable) {
279
584
  runCatching {
280
585
  val sharerUrl =
281
- if (templateId != null) {
586
+ if (requestUrl != null) {
587
+ WebSharerClient.instance.makeScrapUrl(
588
+ requestUrl,
589
+ templateId = templateId?.toLong(),
590
+ templateArgs = templateArgs?.toStringMap(),
591
+ serverCallbackArgs = serverCallbackArgs?.toStringMap(),
592
+ )
593
+ } else if (templateId != null) {
282
594
  WebSharerClient.instance.makeCustomUrl(
283
595
  templateId.toLong(),
284
596
  templateArgs = templateArgs?.toStringMap(),
@@ -297,13 +609,13 @@ class RNCKakaoShareModule internal constructor(
297
609
  }
298
610
  try {
299
611
  KakaoCustomTabsClient.openWithDefault(context, sharerUrl)
300
- promise.resolve(42)
612
+ promise.resolve(result)
301
613
  return
302
614
  } catch (_: UnsupportedOperationException) {
303
615
  }
304
616
  try {
305
617
  KakaoCustomTabsClient.open(context, sharerUrl)
306
- promise.resolve(42)
618
+ promise.resolve(result)
307
619
  return
308
620
  } catch (_: ActivityNotFoundException) {
309
621
  }
@@ -1,5 +1,6 @@
1
1
  package net.mjstudio.rnkakao.share
2
2
 
3
+ import android.net.Uri
3
4
  import com.facebook.react.bridge.ReadableMap
4
5
  import com.kakao.sdk.template.model.Button
5
6
  import com.kakao.sdk.template.model.CalendarTemplate
@@ -41,10 +42,12 @@ object RNCKakaoShareTemplates {
41
42
  Link(
42
43
  webUrl = getString("webUrl"),
43
44
  mobileWebUrl = getString("mobileWebUrl"),
44
- androidExecutionParams = getMap("androidExecutionParams")?.toStringMap(),
45
- iosExecutionParams = getMap("iosExecutionParams")?.toStringMap(),
45
+ androidExecutionParams = getMap("androidExecutionParams")?.toExecutionParams(),
46
+ iosExecutionParams = getMap("iosExecutionParams")?.toExecutionParams(),
46
47
  )
47
48
 
49
+ private fun ReadableMap.toExecutionParams() = toStringMap().entries.associate { (key, value) -> Uri.encode(key) to Uri.encode(value) }
50
+
48
51
  private fun ReadableMap.toContent() =
49
52
  Content(
50
53
  title = getString("title"),
@@ -13,6 +13,63 @@
13
13
 
14
14
  RCT_EXPORT_MODULE()
15
15
 
16
+ RCT_EXPORT_METHOD(isKakaoTalkSharingAvailable : (RCTPromiseResolveBlock)
17
+ resolve reject : (RCTPromiseRejectBlock)reject) {
18
+ [[self manager] isKakaoTalkSharingAvailable:resolve];
19
+ }
20
+
21
+ RCT_EXPORT_METHOD(makeTemplateUrl : (NSString*)templateType templateId : (
22
+ double)templateId templateJson : (NSDictionary*)templateJson templateArgs : (NSDictionary*)
23
+ templateArgs serverCallbackArgs : (NSDictionary*)
24
+ serverCallbackArgs resolve : (RCTPromiseResolveBlock)
25
+ resolve reject : (RCTPromiseRejectBlock)reject) {
26
+ [[self manager] makeTemplateUrl:templateType
27
+ templateId:templateId
28
+ templateJson:templateJson
29
+ templateArgs:templateArgs
30
+ serverCallbackArgs:serverCallbackArgs
31
+ resolve:resolve
32
+ reject:reject];
33
+ }
34
+
35
+ RCT_EXPORT_METHOD(uploadImage : (NSString*)imageUri secureResource : (BOOL)
36
+ secureResource resolve : (RCTPromiseResolveBlock)
37
+ resolve reject : (RCTPromiseRejectBlock)reject) {
38
+ [[self manager] uploadImage:imageUri secureResource:secureResource resolve:resolve reject:reject];
39
+ }
40
+
41
+ RCT_EXPORT_METHOD(getTemplateDiagnostics : (NSString*)templateType templateId : (
42
+ double)templateId templateJson : (NSDictionary*)templateJson templateArgs : (NSDictionary*)
43
+ templateArgs serverCallbackArgs : (NSDictionary*)
44
+ serverCallbackArgs pickerSettings : (NSDictionary*)
45
+ pickerSettings resolve : (RCTPromiseResolveBlock)
46
+ resolve reject : (RCTPromiseRejectBlock)reject) {
47
+ [[self manager] getTemplateDiagnostics:templateType
48
+ templateId:templateId
49
+ templateJson:templateJson
50
+ templateArgs:templateArgs
51
+ serverCallbackArgs:serverCallbackArgs
52
+ pickerSettings:pickerSettings
53
+ resolve:resolve
54
+ reject:reject];
55
+ }
56
+
57
+ RCT_EXPORT_METHOD(
58
+ shareScrapTemplate : (NSString*)requestUrl useWebBrowserIfKakaoTalkNotAvailable : (BOOL)
59
+ useWebBrowserIfKakaoTalkNotAvailable templateId : (NSNumber*)templateId templateArgs : (
60
+ NSDictionary*)templateArgs serverCallbackArgs : (NSDictionary*)
61
+ serverCallbackArgs pickerSettings : (NSDictionary*)pickerSettings resolve : (
62
+ RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject) {
63
+ [[self manager] shareScrapTemplate:requestUrl
64
+ useWebBrowserIfKakaoTalkNotAvailable:useWebBrowserIfKakaoTalkNotAvailable
65
+ templateId:templateId
66
+ templateArgs:templateArgs
67
+ serverCallbackArgs:serverCallbackArgs
68
+ pickerSettings:pickerSettings
69
+ resolve:resolve
70
+ reject:reject];
71
+ }
72
+
16
73
  RCT_EXPORT_METHOD(scrapImage : (NSString*)imageUrl secureResource : (BOOL)secureResource resolve : (
17
74
  RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject) {
18
75
  [[self manager] scrapImage:imageUrl secureResource:secureResource resolve:resolve reject:reject];
@@ -26,11 +83,12 @@ RCT_EXPORT_METHOD(scrapImage : (NSString*)imageUrl secureResource : (BOOL)secure
26
83
  // RNC_KAKAO_SHARE_EXPORT_DEFAULT_TEMPLATE(shareCalendarTemplate, calendar)
27
84
 
28
85
  RCT_EXPORT_METHOD(
29
- shareOrSendMeOrSendFriendOrWhatever : (NSString*)sendType templateType : (NSString*)
30
- templateType templateId : (double)templateId templateJson : (NSDictionary*)templateJson
31
- receiverUuids : (NSArray*)receiverUuids useWebBrowserIfKakaoTalkNotAvailable : (BOOL)
32
- useWebBrowserIfKakaoTalkNotAvailable templateArgs : (NSDictionary*)
33
- templateArgs serverCallbackArgs : (NSDictionary*)serverCallbackArgs resolve : (
86
+ shareOrSendMeOrSendFriendOrWhatever : (NSString*)sendType templateType : (NSString*)templateType
87
+ templateId : (double)templateId templateJson : (NSDictionary*)templateJson receiverUuids : (
88
+ NSArray*)receiverUuids useWebBrowserIfKakaoTalkNotAvailable : (BOOL)
89
+ useWebBrowserIfKakaoTalkNotAvailable templateArgs : (NSDictionary*)
90
+ templateArgs serverCallbackArgs : (NSDictionary*)
91
+ serverCallbackArgs pickerSettings : (NSDictionary*)pickerSettings resolve : (
34
92
  RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject) {
35
93
  [[self manager] shareOrSendMeOrSendFriendOrWhatever:sendType
36
94
  templateType:templateType
@@ -40,6 +98,7 @@ RCT_EXPORT_METHOD(
40
98
  useWebBrowserIfKakaoTalkNotAvailable:useWebBrowserIfKakaoTalkNotAvailable
41
99
  templateArgs:templateArgs
42
100
  serverCallbackArgs:serverCallbackArgs
101
+ pickerSettings:pickerSettings
43
102
  resolve:resolve
44
103
  reject:reject];
45
104
  }