@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.
- package/CHANGELOG.md +33 -0
- package/RNCKakaoShare.podspec +0 -1
- package/android/build.gradle +1 -2
- package/android/src/main/java/net/mjstudio/rnkakao/share/RNCKakaoShareModule.kt +321 -12
- package/android/src/main/java/net/mjstudio/rnkakao/share/RNCKakaoShareTemplates.kt +5 -2
- package/ios/RNCKakaoShare.mm +64 -5
- package/ios/RNCKakaoShareManager.swift +315 -37
- package/lib/commonjs/index.js +140 -30
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +199 -21
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/spec/NativeKakaoShare.ts +77 -4
- package/lib/commonjs/validateSharePickerSettings.js +33 -0
- package/lib/commonjs/validateSharePickerSettings.js.map +1 -0
- package/lib/module/index.js +131 -30
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +190 -21
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/spec/NativeKakaoShare.ts +77 -4
- package/lib/module/validateSharePickerSettings.js +29 -0
- package/lib/module/validateSharePickerSettings.js.map +1 -0
- package/lib/typescript/src/index.d.ts +97 -37
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/spec/NativeKakaoShare.d.ts +72 -1
- package/lib/typescript/src/spec/NativeKakaoShare.d.ts.map +1 -1
- package/lib/typescript/src/validateSharePickerSettings.d.ts +6 -0
- package/lib/typescript/src/validateSharePickerSettings.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/index.ts +278 -17
- package/src/index.web.ts +234 -38
- package/src/spec/NativeKakaoShare.ts +77 -4
- package/src/validateSharePickerSettings.ts +38 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,39 @@
|
|
|
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.2
|
|
7
|
+
|
|
8
|
+
### Patch Changes
|
|
9
|
+
|
|
10
|
+
- f466ffa: Normalize APIs without success data to resolve without a value across platforms, while preserving friend-message results.
|
|
11
|
+
- @react-native-kakao/core@3.1.0-next.2
|
|
12
|
+
|
|
13
|
+
## 3.1.0-next.1
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- d117308: Add local image uploads on Android, iOS, and web with image metadata and secure URL options.
|
|
18
|
+
- 483fd00: Add URL scrap messages to My Chatroom and friends on Android, iOS, and web.
|
|
19
|
+
- bf027c0: Add URL-scraped message sharing with custom template arguments and native browser fallback on Android, iOS, and web.
|
|
20
|
+
- ff35f20: Expose native URL builders for default, custom, and scraped-page sharing without launching a sharing interface. Report unsupported URL building explicitly on web.
|
|
21
|
+
|
|
22
|
+
Encode Android template execution-parameter keys and values before the SDK serializes them, preserving special characters across sharing URLs, sharing, and message sending.
|
|
23
|
+
- 1efca29: Expose Kakao Talk sharing availability and Kakao Navi installation checks on Android and iOS, with explicit false results on web.
|
|
24
|
+
- ceafbcf: Add optional friend message results with successful recipients and failure details on Android, iOS, and web.
|
|
25
|
+
- 314d493: Expose validated share target picker settings across native and web share templates.
|
|
26
|
+
- 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.
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- 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.
|
|
31
|
+
- Updated dependencies [d5c5fb8]
|
|
32
|
+
- Updated dependencies [3027207]
|
|
33
|
+
- Updated dependencies [dfd32ca]
|
|
34
|
+
- Updated dependencies [2b223bf]
|
|
35
|
+
- Updated dependencies [67cd4e2]
|
|
36
|
+
- Updated dependencies [d81f9b7]
|
|
37
|
+
- @react-native-kakao/core@3.1.0-next.1
|
|
38
|
+
|
|
6
39
|
## 3.1.0-next.0
|
|
7
40
|
|
|
8
41
|
### Minor Changes
|
package/RNCKakaoShare.podspec
CHANGED
package/android/build.gradle
CHANGED
|
@@ -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,15 +422,18 @@ 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) {
|
|
180
429
|
promise.rejectWith(e)
|
|
181
430
|
} else {
|
|
182
|
-
promise.resolve(
|
|
431
|
+
promise.resolve(null)
|
|
183
432
|
}
|
|
184
433
|
}
|
|
185
|
-
if (
|
|
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(
|
|
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 (
|
|
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,9 +507,12 @@ 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
|
|
@@ -247,20 +522,45 @@ class RNCKakaoShareModule internal constructor(
|
|
|
247
522
|
if (error != null) {
|
|
248
523
|
promise.rejectWith(error)
|
|
249
524
|
} else if (sharingResult != null) {
|
|
250
|
-
|
|
251
|
-
|
|
525
|
+
if (diagnosticsOnly) {
|
|
526
|
+
promise.resolve(
|
|
527
|
+
argMap().apply {
|
|
528
|
+
putMap("warningMsg", argMap().apply { sharingResult.warningMsg.forEach { (key, value) -> putString(key, value) } })
|
|
529
|
+
putMap("argumentMsg", argMap().apply { sharingResult.argumentMsg.forEach { (key, value) -> putString(key, value) } })
|
|
530
|
+
},
|
|
531
|
+
)
|
|
532
|
+
} else {
|
|
533
|
+
context.startActivity(sharingResult.intent)
|
|
534
|
+
promise.resolve(null)
|
|
535
|
+
}
|
|
252
536
|
} else {
|
|
253
|
-
promise.
|
|
537
|
+
promise.rejectWith(RNCKakaoResponseNotFoundException("sharingResult"))
|
|
254
538
|
}
|
|
255
539
|
}
|
|
256
540
|
|
|
257
541
|
if (ShareClient.instance.isKakaoTalkSharingAvailable(context)) {
|
|
258
|
-
|
|
542
|
+
val pickerType = pickerSettings?.takeIf { it.hasKey("type") }?.getString("type")
|
|
543
|
+
val shareType = ShareType.entries.firstOrNull { it.value == pickerType }
|
|
544
|
+
val limit = pickerSettings?.takeIf { it.hasKey("limit") }?.getDouble("limit")?.toInt()
|
|
545
|
+
if (requestUrl != null) {
|
|
546
|
+
ShareClient.instance.shareScrap(
|
|
547
|
+
context,
|
|
548
|
+
requestUrl,
|
|
549
|
+
templateId = templateId?.toLong(),
|
|
550
|
+
templateArgs = templateArgs?.toStringMap(),
|
|
551
|
+
serverCallbackArgs = serverCallbackArgs?.toStringMap(),
|
|
552
|
+
shareType = shareType,
|
|
553
|
+
limit = limit,
|
|
554
|
+
callback = callback,
|
|
555
|
+
)
|
|
556
|
+
} else if (templateId != null) {
|
|
259
557
|
ShareClient.instance.shareCustom(
|
|
260
558
|
context,
|
|
261
559
|
templateId.toLong(),
|
|
262
560
|
templateArgs = templateArgs?.toStringMap(),
|
|
263
561
|
serverCallbackArgs = serverCallbackArgs?.toStringMap(),
|
|
562
|
+
shareType = shareType,
|
|
563
|
+
limit = limit,
|
|
264
564
|
callback = callback,
|
|
265
565
|
)
|
|
266
566
|
} else if (defaultTemplate != null) {
|
|
@@ -269,6 +569,8 @@ class RNCKakaoShareModule internal constructor(
|
|
|
269
569
|
context,
|
|
270
570
|
RNCKakaoShareTemplates.createDefaultTemplate(defaultTemplate, templateType),
|
|
271
571
|
serverCallbackArgs = serverCallbackArgs?.toStringMap(),
|
|
572
|
+
shareType = shareType,
|
|
573
|
+
limit = limit,
|
|
272
574
|
callback = callback,
|
|
273
575
|
)
|
|
274
576
|
}.onFailure {
|
|
@@ -278,7 +580,14 @@ class RNCKakaoShareModule internal constructor(
|
|
|
278
580
|
} else if (useWebBrowserIfKakaoTalkNotAvailable) {
|
|
279
581
|
runCatching {
|
|
280
582
|
val sharerUrl =
|
|
281
|
-
if (
|
|
583
|
+
if (requestUrl != null) {
|
|
584
|
+
WebSharerClient.instance.makeScrapUrl(
|
|
585
|
+
requestUrl,
|
|
586
|
+
templateId = templateId?.toLong(),
|
|
587
|
+
templateArgs = templateArgs?.toStringMap(),
|
|
588
|
+
serverCallbackArgs = serverCallbackArgs?.toStringMap(),
|
|
589
|
+
)
|
|
590
|
+
} else if (templateId != null) {
|
|
282
591
|
WebSharerClient.instance.makeCustomUrl(
|
|
283
592
|
templateId.toLong(),
|
|
284
593
|
templateArgs = templateArgs?.toStringMap(),
|
|
@@ -297,13 +606,13 @@ class RNCKakaoShareModule internal constructor(
|
|
|
297
606
|
}
|
|
298
607
|
try {
|
|
299
608
|
KakaoCustomTabsClient.openWithDefault(context, sharerUrl)
|
|
300
|
-
promise.resolve(
|
|
609
|
+
promise.resolve(null)
|
|
301
610
|
return
|
|
302
611
|
} catch (_: UnsupportedOperationException) {
|
|
303
612
|
}
|
|
304
613
|
try {
|
|
305
614
|
KakaoCustomTabsClient.open(context, sharerUrl)
|
|
306
|
-
promise.resolve(
|
|
615
|
+
promise.resolve(null)
|
|
307
616
|
return
|
|
308
617
|
} catch (_: ActivityNotFoundException) {
|
|
309
618
|
}
|
|
@@ -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")?.
|
|
45
|
-
iosExecutionParams = getMap("iosExecutionParams")?.
|
|
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"),
|
package/ios/RNCKakaoShare.mm
CHANGED
|
@@ -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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
}
|