@react-native-kakao/share 3.0.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.
- package/CHANGELOG.md +41 -0
- package/RNCKakaoShare.podspec +0 -1
- package/android/build.gradle +1 -2
- package/android/src/main/java/net/mjstudio/rnkakao/share/RNCKakaoShareModule.kt +359 -11
- package/android/src/main/java/net/mjstudio/rnkakao/share/RNCKakaoShareTemplates.kt +5 -2
- package/ios/RNCKakaoShare.mm +69 -5
- package/ios/RNCKakaoShareManager.swift +349 -36
- package/lib/commonjs/index.js +145 -29
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +267 -48
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/spec/NativeKakaoShare.ts +89 -3
- package/lib/commonjs/validateSharePickerSettings.js +33 -0
- package/lib/commonjs/validateSharePickerSettings.js.map +1 -0
- package/lib/module/index.js +135 -29
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +258 -49
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/spec/NativeKakaoShare.ts +89 -3
- package/lib/module/validateSharePickerSettings.js +29 -0
- package/lib/module/validateSharePickerSettings.js.map +1 -0
- package/lib/typescript/src/index.d.ts +88 -23
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/spec/NativeKakaoShare.d.ts +84 -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 +5 -5
- package/src/index.ts +271 -15
- package/src/index.web.ts +305 -62
- package/src/spec/NativeKakaoShare.ts +89 -3
- package/src/validateSharePickerSettings.ts +38 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,47 @@
|
|
|
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
|
+
|
|
32
|
+
## 3.1.0-next.0
|
|
33
|
+
|
|
34
|
+
### Minor Changes
|
|
35
|
+
|
|
36
|
+
- ea4208b: Add image URL scraping with consistent image metadata on Android, iOS, and web.
|
|
37
|
+
|
|
38
|
+
### Patch Changes
|
|
39
|
+
|
|
40
|
+
- 4772981: Use `reactApplicationContext.currentActivity` in the Android modules instead of the bare `currentActivity` getter, so they compile on React Native releases where `ReactContextBaseJavaModule` no longer exposes it to Kotlin subclasses.
|
|
41
|
+
- 71700aa: Align web SDK options, response shapes, timestamps, and session errors with native APIs.
|
|
42
|
+
- Updated dependencies [20c253b]
|
|
43
|
+
- Updated dependencies [3260517]
|
|
44
|
+
- Updated dependencies [71700aa]
|
|
45
|
+
- @react-native-kakao/core@3.1.0-next.0
|
|
46
|
+
|
|
6
47
|
## 3.0.0
|
|
7
48
|
|
|
8
49
|
### Major 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,257 @@ 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
|
+
|
|
244
|
+
@ReactMethod
|
|
245
|
+
override fun scrapImage(
|
|
246
|
+
imageUrl: String,
|
|
247
|
+
secureResource: Boolean,
|
|
248
|
+
promise: Promise,
|
|
249
|
+
) = onMain {
|
|
250
|
+
ShareClient.instance.scrapImage(imageUrl, secureResource) { result, error ->
|
|
251
|
+
if (error != null) {
|
|
252
|
+
promise.rejectWith(error)
|
|
253
|
+
} else if (result != null) {
|
|
254
|
+
val original = result.infos.original
|
|
255
|
+
promise.resolve(
|
|
256
|
+
argMap().apply {
|
|
257
|
+
putMap(
|
|
258
|
+
"infos",
|
|
259
|
+
argMap().apply {
|
|
260
|
+
putMap(
|
|
261
|
+
"original",
|
|
262
|
+
argMap().apply {
|
|
263
|
+
putString("url", original.url)
|
|
264
|
+
putString("contentType", original.contentType)
|
|
265
|
+
putDouble("length", original.length.toDouble())
|
|
266
|
+
putDouble("width", original.width.toDouble())
|
|
267
|
+
putDouble("height", original.height.toDouble())
|
|
268
|
+
},
|
|
269
|
+
)
|
|
270
|
+
},
|
|
271
|
+
)
|
|
272
|
+
},
|
|
273
|
+
)
|
|
274
|
+
} else {
|
|
275
|
+
promise.rejectWith(RNCKakaoResponseNotFoundException("imageUploadResult"))
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
30
280
|
@ReactMethod
|
|
31
281
|
override fun shareOrSendMeOrSendFriendOrWhatever(
|
|
32
282
|
sendType: String,
|
|
@@ -37,6 +287,7 @@ class RNCKakaoShareModule internal constructor(
|
|
|
37
287
|
useWebBrowserIfKakaoTalkNotAvailable: Boolean,
|
|
38
288
|
templateArgs: ReadableMap,
|
|
39
289
|
serverCallbackArgs: ReadableMap,
|
|
290
|
+
pickerSettings: ReadableMap?,
|
|
40
291
|
promise: Promise,
|
|
41
292
|
) = onMain {
|
|
42
293
|
if (templateType == "custom") {
|
|
@@ -48,8 +299,36 @@ class RNCKakaoShareModule internal constructor(
|
|
|
48
299
|
useWebBrowserIfKakaoTalkNotAvailable,
|
|
49
300
|
templateArgs,
|
|
50
301
|
serverCallbackArgs,
|
|
302
|
+
pickerSettings,
|
|
51
303
|
promise,
|
|
52
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
|
+
}
|
|
53
332
|
} else {
|
|
54
333
|
shareOrSendDefaultTemplate(
|
|
55
334
|
sendType,
|
|
@@ -58,6 +337,7 @@ class RNCKakaoShareModule internal constructor(
|
|
|
58
337
|
receiverUuids = receiverUuids.filterIsInstance<String>(),
|
|
59
338
|
useWebBrowserIfKakaoTalkNotAvailable,
|
|
60
339
|
serverCallbackArgs,
|
|
340
|
+
pickerSettings,
|
|
61
341
|
promise,
|
|
62
342
|
)
|
|
63
343
|
}
|
|
@@ -71,6 +351,7 @@ class RNCKakaoShareModule internal constructor(
|
|
|
71
351
|
useWebBrowserIfKakaoTalkNotAvailable: Boolean,
|
|
72
352
|
templateArgs: ReadableMap?,
|
|
73
353
|
serverCallbackArgs: ReadableMap?,
|
|
354
|
+
pickerSettings: ReadableMap?,
|
|
74
355
|
promise: Promise,
|
|
75
356
|
) = when (sendType) {
|
|
76
357
|
"share" -> {
|
|
@@ -81,6 +362,7 @@ class RNCKakaoShareModule internal constructor(
|
|
|
81
362
|
useWebBrowserIfKakaoTalkNotAvailable,
|
|
82
363
|
templateArgs,
|
|
83
364
|
serverCallbackArgs,
|
|
365
|
+
pickerSettings,
|
|
84
366
|
promise,
|
|
85
367
|
)
|
|
86
368
|
}
|
|
@@ -105,6 +387,7 @@ class RNCKakaoShareModule internal constructor(
|
|
|
105
387
|
receiverUuids: List<String>,
|
|
106
388
|
useWebBrowserIfKakaoTalkNotAvailable: Boolean,
|
|
107
389
|
serverCallbackArgs: ReadableMap?,
|
|
390
|
+
pickerSettings: ReadableMap?,
|
|
108
391
|
promise: Promise,
|
|
109
392
|
) = when (sendType) {
|
|
110
393
|
"share" -> {
|
|
@@ -115,6 +398,7 @@ class RNCKakaoShareModule internal constructor(
|
|
|
115
398
|
useWebBrowserIfKakaoTalkNotAvailable,
|
|
116
399
|
argMap(),
|
|
117
400
|
serverCallbackArgs,
|
|
401
|
+
pickerSettings,
|
|
118
402
|
promise,
|
|
119
403
|
)
|
|
120
404
|
}
|
|
@@ -138,6 +422,7 @@ class RNCKakaoShareModule internal constructor(
|
|
|
138
422
|
defaultTemplate: ReadableMap? = null,
|
|
139
423
|
templateArgs: ReadableMap? = null,
|
|
140
424
|
promise: Promise,
|
|
425
|
+
requestUrl: String? = null,
|
|
141
426
|
) {
|
|
142
427
|
val callback = { e: Throwable? ->
|
|
143
428
|
if (e != null) {
|
|
@@ -146,7 +431,9 @@ class RNCKakaoShareModule internal constructor(
|
|
|
146
431
|
promise.resolve(42)
|
|
147
432
|
}
|
|
148
433
|
}
|
|
149
|
-
if (
|
|
434
|
+
if (requestUrl != null) {
|
|
435
|
+
TalkApiClient.instance.sendScrapMemo(requestUrl, templateId?.toLong(), templateArgs?.toStringMap(), callback)
|
|
436
|
+
} else if (templateId != null) {
|
|
150
437
|
TalkApiClient.instance.sendCustomMemo(templateId.toLong(), templateArgs?.toStringMap(), callback)
|
|
151
438
|
} else if (defaultTemplate != null) {
|
|
152
439
|
runCatching {
|
|
@@ -167,6 +454,7 @@ class RNCKakaoShareModule internal constructor(
|
|
|
167
454
|
defaultTemplate: ReadableMap? = null,
|
|
168
455
|
templateArgs: ReadableMap? = null,
|
|
169
456
|
promise: Promise,
|
|
457
|
+
requestUrl: String? = null,
|
|
170
458
|
) {
|
|
171
459
|
val callback = { messageSendResult: MessageSendResult?, e: Throwable? ->
|
|
172
460
|
if (e != null) {
|
|
@@ -174,10 +462,30 @@ class RNCKakaoShareModule internal constructor(
|
|
|
174
462
|
} else if (messageSendResult == null) {
|
|
175
463
|
promise.rejectWith(RNCKakaoResponseNotFoundException("messageSendResult"))
|
|
176
464
|
} else {
|
|
177
|
-
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
|
+
)
|
|
178
484
|
}
|
|
179
485
|
}
|
|
180
|
-
if (
|
|
486
|
+
if (requestUrl != null) {
|
|
487
|
+
TalkApiClient.instance.sendScrapMessage(receiverUuids, requestUrl, templateId?.toLong(), templateArgs?.toStringMap(), callback)
|
|
488
|
+
} else if (templateId != null) {
|
|
181
489
|
TalkApiClient.instance.sendCustomMessage(receiverUuids, templateId.toLong(), templateArgs?.toStringMap(), callback)
|
|
182
490
|
} else if (defaultTemplate != null) {
|
|
183
491
|
runCatching {
|
|
@@ -199,32 +507,63 @@ class RNCKakaoShareModule internal constructor(
|
|
|
199
507
|
useWebBrowserIfKakaoTalkNotAvailable: Boolean,
|
|
200
508
|
templateArgs: ReadableMap? = null,
|
|
201
509
|
serverCallbackArgs: ReadableMap? = null,
|
|
510
|
+
pickerSettings: ReadableMap?,
|
|
202
511
|
promise: Promise,
|
|
512
|
+
requestUrl: String? = null,
|
|
513
|
+
diagnosticsOnly: Boolean = false,
|
|
203
514
|
) {
|
|
204
|
-
val context = currentActivity
|
|
515
|
+
val context = if (diagnosticsOnly) reactApplicationContext else reactApplicationContext.currentActivity
|
|
205
516
|
if (context == null) {
|
|
206
517
|
promise.rejectWith(ActivityNotFoundException())
|
|
207
518
|
return
|
|
208
519
|
}
|
|
209
520
|
|
|
521
|
+
val result = if (requestUrl != null) null else 42
|
|
210
522
|
val callback = { sharingResult: SharingResult?, error: Throwable? ->
|
|
211
523
|
if (error != null) {
|
|
212
524
|
promise.rejectWith(error)
|
|
213
525
|
} else if (sharingResult != null) {
|
|
214
|
-
|
|
215
|
-
|
|
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"))
|
|
216
539
|
} else {
|
|
217
|
-
promise.resolve(
|
|
540
|
+
promise.resolve(result)
|
|
218
541
|
}
|
|
219
542
|
}
|
|
220
543
|
|
|
221
544
|
if (ShareClient.instance.isKakaoTalkSharingAvailable(context)) {
|
|
222
|
-
|
|
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) {
|
|
223
560
|
ShareClient.instance.shareCustom(
|
|
224
561
|
context,
|
|
225
562
|
templateId.toLong(),
|
|
226
563
|
templateArgs = templateArgs?.toStringMap(),
|
|
227
564
|
serverCallbackArgs = serverCallbackArgs?.toStringMap(),
|
|
565
|
+
shareType = shareType,
|
|
566
|
+
limit = limit,
|
|
228
567
|
callback = callback,
|
|
229
568
|
)
|
|
230
569
|
} else if (defaultTemplate != null) {
|
|
@@ -233,6 +572,8 @@ class RNCKakaoShareModule internal constructor(
|
|
|
233
572
|
context,
|
|
234
573
|
RNCKakaoShareTemplates.createDefaultTemplate(defaultTemplate, templateType),
|
|
235
574
|
serverCallbackArgs = serverCallbackArgs?.toStringMap(),
|
|
575
|
+
shareType = shareType,
|
|
576
|
+
limit = limit,
|
|
236
577
|
callback = callback,
|
|
237
578
|
)
|
|
238
579
|
}.onFailure {
|
|
@@ -242,7 +583,14 @@ class RNCKakaoShareModule internal constructor(
|
|
|
242
583
|
} else if (useWebBrowserIfKakaoTalkNotAvailable) {
|
|
243
584
|
runCatching {
|
|
244
585
|
val sharerUrl =
|
|
245
|
-
if (
|
|
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) {
|
|
246
594
|
WebSharerClient.instance.makeCustomUrl(
|
|
247
595
|
templateId.toLong(),
|
|
248
596
|
templateArgs = templateArgs?.toStringMap(),
|
|
@@ -261,13 +609,13 @@ class RNCKakaoShareModule internal constructor(
|
|
|
261
609
|
}
|
|
262
610
|
try {
|
|
263
611
|
KakaoCustomTabsClient.openWithDefault(context, sharerUrl)
|
|
264
|
-
promise.resolve(
|
|
612
|
+
promise.resolve(result)
|
|
265
613
|
return
|
|
266
614
|
} catch (_: UnsupportedOperationException) {
|
|
267
615
|
}
|
|
268
616
|
try {
|
|
269
617
|
KakaoCustomTabsClient.open(context, sharerUrl)
|
|
270
|
-
promise.resolve(
|
|
618
|
+
promise.resolve(result)
|
|
271
619
|
return
|
|
272
620
|
} catch (_: ActivityNotFoundException) {
|
|
273
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")?.
|
|
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"),
|