react-native-smartlinks 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/android/build.gradle +33 -0
  2. package/android/src/main/AndroidManifest.xml +4 -0
  3. package/android/src/main/java/live/smartlinks/reactnative/SmartLinksActivityLifecycle.kt +34 -0
  4. package/android/src/main/java/live/smartlinks/reactnative/SmartLinksBridgeHandler.kt +172 -0
  5. package/android/src/main/java/live/smartlinks/reactnative/SmartLinksModule.kt +299 -0
  6. package/android/src/main/java/live/smartlinks/reactnative/SmartLinksPackage.kt +16 -0
  7. package/ios/Linklytics/DeviceInfo.swift +114 -0
  8. package/ios/Linklytics/Linklytics.swift +581 -0
  9. package/ios/Linklytics/LinklyticsInterface.swift +10 -0
  10. package/ios/Linklytics/Managers/BatchEventManager.swift +218 -0
  11. package/ios/Linklytics/Managers/OfflineCache.swift +35 -0
  12. package/ios/Linklytics/Managers/SQLiteStorage.swift +225 -0
  13. package/ios/Linklytics/Models/AppResponse.swift +16 -0
  14. package/ios/Linklytics/Models/DeepLinkRoute.swift +24 -0
  15. package/ios/Linklytics/Models/DeferredLinkResponse.swift +81 -0
  16. package/ios/Linklytics/Models/DynamicLinkResponse.swift +13 -0
  17. package/ios/Linklytics/Models/EventResponse.swift +14 -0
  18. package/ios/Linklytics/Models/OfflineEvent.swift +80 -0
  19. package/ios/Linklytics/NetworkManager.swift +360 -0
  20. package/ios/Linklytics/SdkConstants.swift +29 -0
  21. package/ios/PrivacyInfo.xcprivacy +14 -0
  22. package/ios/SmartLinksModule.m +150 -0
  23. package/ios/SmartLinksModule.swift +281 -0
  24. package/package.json +41 -0
  25. package/react-native-smartlinks.podspec +27 -0
  26. package/react-native.config.js +12 -0
  27. package/src/index.ts +84 -0
@@ -0,0 +1,281 @@
1
+ import Foundation
2
+ import React
3
+ #if canImport(SmartLinksSDKCore)
4
+ import SmartLinksSDKCore
5
+ #elseif canImport(SmartLinksSDK)
6
+ import SmartLinksSDK
7
+ #endif
8
+
9
+ @objc(SmartLinksModule)
10
+ class SmartLinksModule: RCTEventEmitter {
11
+
12
+ private var hasListeners = false
13
+
14
+ override static func requiresMainQueueSetup() -> Bool {
15
+ return true
16
+ }
17
+
18
+ override func supportedEvents() -> [String]! {
19
+ return ["SmartLinksDeepLink"]
20
+ }
21
+
22
+ override func startObserving() {
23
+ hasListeners = true
24
+ SmartLinksSdk.shared.setOnLinkReceivedListener { [weak self] route in
25
+ self?.emitDeepLink(route)
26
+ }
27
+ }
28
+
29
+ override func stopObserving() {
30
+ hasListeners = false
31
+ }
32
+
33
+ @objc(initialize:debugMode:resolver:rejecter:)
34
+ func initialize(_ apiKey: String, debugMode: Bool, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
35
+ SmartLinksSdk.shared.initialize(apiKey: apiKey, debugMode: debugMode)
36
+ SmartLinksSdk.shared.setOnLinkReceivedListener { [weak self] route in
37
+ guard self?.hasListeners == true else { return }
38
+ self?.emitDeepLink(route)
39
+ }
40
+ resolver(true)
41
+ }
42
+
43
+ @objc(getAppUserId:rejecter:)
44
+ func getAppUserId(_ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
45
+ resolver(SmartLinksIdentity.getAppUserId())
46
+ }
47
+
48
+ @objc(sendEvent:params:resolver:rejecter:)
49
+ func sendEvent(_ eventName: String, params: [String: Any], resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
50
+ let parameters = params.mapValues { $0 as Any? }
51
+ SmartLinksSdk.shared.sendEvent(eventName, parameters: parameters)
52
+ resolver(nil)
53
+ }
54
+
55
+ @objc(generateLink:params:shortLink:resolver:rejecter:)
56
+ func generateLink(_ route: String, params: [String: Any], shortLink: Bool, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
57
+ let stringParams = params.mapValues { "\($0)" }
58
+ let link = SmartLinksSdk.shared.generateDynamicLink(route, parameters: stringParams, isShort: shortLink)
59
+ resolver(link)
60
+ }
61
+
62
+ @objc(registerLinkListener:rejecter:)
63
+ func registerLinkListener(_ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
64
+ if let route = SmartLinksSdk.shared.getLink() {
65
+ emitDeepLink(route)
66
+ }
67
+ resolver(nil)
68
+ }
69
+
70
+ @objc(fetchApps:rejecter:)
71
+ func fetchApps(_ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
72
+ SmartLinksBridgeAPI.fetchApps { json in
73
+ resolver(json)
74
+ }
75
+ }
76
+
77
+ @objc(submitFeedback:resolver:rejecter:)
78
+ func submitFeedback(_ args: [String: Any], resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
79
+ SmartLinksBridgeAPI.submitFeedback(
80
+ content: args["content"] as? String ?? "",
81
+ platform: args["platform"] as? String ?? "ios",
82
+ version: args["version"] as? String ?? "1.0",
83
+ name: args["name"] as? String,
84
+ email: args["email"] as? String,
85
+ isPremium: args["isPremium"] as? Bool ?? false,
86
+ attachmentPath: args["attachmentPath"] as? String,
87
+ completion: { json in resolver(json) }
88
+ )
89
+ }
90
+
91
+ @objc(fetchAds:resolver:rejecter:)
92
+ func fetchAds(_ type: String?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
93
+ SmartLinksBridgeAPI.fetchAds(type: type) { json in
94
+ resolver(json)
95
+ }
96
+ }
97
+
98
+ @objc(trackAdImpression:resolver:rejecter:)
99
+ func trackAdImpression(_ adId: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
100
+ SmartLinksBridgeAPI.trackAdImpression(adId: adId.intValue) { json in
101
+ resolver(json)
102
+ }
103
+ }
104
+
105
+ @objc(trackAdClick:resolver:rejecter:)
106
+ func trackAdClick(_ adId: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
107
+ SmartLinksBridgeAPI.trackAdClick(adId: adId.intValue) { json in
108
+ resolver(json)
109
+ }
110
+ }
111
+
112
+ @objc(processAi:files:resolver:rejecter:)
113
+ func processAi(_ instructionsJson: String, files: [String: String], resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
114
+ SmartLinksBridgeAPI.processAi(instructionsJson: instructionsJson, files: files) { json in
115
+ resolver(json)
116
+ }
117
+ }
118
+
119
+ @objc(validatePromoCode:resolver:rejecter:)
120
+ func validatePromoCode(_ code: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
121
+ SmartLinksBridgeAPI.validatePromoCode(code) { json in
122
+ resolver(json)
123
+ }
124
+ }
125
+
126
+ @objc(redeemPromoCode:resolver:rejecter:)
127
+ func redeemPromoCode(_ code: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
128
+ SmartLinksBridgeAPI.redeemPromoCode(code) { json in
129
+ resolver(json)
130
+ }
131
+ }
132
+
133
+ @objc(verifyGooglePurchase:token:resolver:rejecter:)
134
+ func verifyGooglePurchase(_ productId: String, token: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
135
+ rejecter("UNSUPPORTED", "Google IAP verification is not supported on iOS", nil)
136
+ }
137
+
138
+ @objc(verifyApplePurchase:resolver:rejecter:)
139
+ func verifyApplePurchase(_ receiptData: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
140
+ SmartLinksBridgeAPI.verifyApplePurchase(receiptData: receiptData) { json in
141
+ resolver(json)
142
+ }
143
+ }
144
+
145
+ @objc(getCommunities:rejecter:)
146
+ func getCommunities(_ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
147
+ SmartLinksBridgeAPI.getCommunities { json in
148
+ resolver(json)
149
+ }
150
+ }
151
+
152
+ @objc(getPosts:authToken:resolver:rejecter:)
153
+ func getPosts(_ communityId: NSNumber, authToken: String?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
154
+ SmartLinksBridgeAPI.getPosts(communityId: communityId.intValue, authToken: authToken) { json in
155
+ resolver(json)
156
+ }
157
+ }
158
+
159
+ @objc(socialAuthGoogle:project:resolver:rejecter:)
160
+ func socialAuthGoogle(_ accessToken: String, project: String?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
161
+ SmartLinksBridgeAPI.socialAuthGoogle(accessToken: accessToken, project: project) { json in
162
+ resolver(json)
163
+ }
164
+ }
165
+
166
+ @objc(getBlogs:search:resolver:rejecter:)
167
+ func getBlogs(_ page: NSNumber, search: String?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
168
+ SmartLinksBridgeAPI.getBlogs(page: page.intValue, search: search) { json in
169
+ resolver(json)
170
+ }
171
+ }
172
+
173
+ @objc(getBlogPost:resolver:rejecter:)
174
+ func getBlogPost(_ slug: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
175
+ SmartLinksBridgeAPI.getBlogPost(slug: slug) { json in
176
+ resolver(json)
177
+ }
178
+ }
179
+
180
+ @objc(getCommunity:rejecter:)
181
+ func getCommunity(_ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
182
+ SmartLinksBridgeAPI.getCommunity { json in resolver(json) }
183
+ }
184
+
185
+ @objc(togglePostLike:authToken:resolver:rejecter:)
186
+ func togglePostLike(_ postId: NSNumber, authToken: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
187
+ SmartLinksBridgeAPI.togglePostLike(postId: postId.intValue, authToken: authToken) { json in
188
+ resolver(json)
189
+ }
190
+ }
191
+
192
+ @objc(createPost:title:content:authToken:resolver:rejecter:)
193
+ func createPost(_ communityId: String, title: String, content: String, authToken: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
194
+ SmartLinksBridgeAPI.createPost(
195
+ communityId: communityId,
196
+ title: title,
197
+ content: content,
198
+ authToken: authToken,
199
+ completion: { json in resolver(json) }
200
+ )
201
+ }
202
+
203
+ @objc(socialAuthApple:project:resolver:rejecter:)
204
+ func socialAuthApple(_ accessToken: String, project: String?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
205
+ SmartLinksBridgeAPI.socialAuthApple(accessToken: accessToken, project: project) { json in
206
+ resolver(json)
207
+ }
208
+ }
209
+
210
+ @objc(getComments:authToken:resolver:rejecter:)
211
+ func getComments(_ postId: String, authToken: String?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
212
+ SmartLinksBridgeAPI.getComments(postId: postId, authToken: authToken) { json in
213
+ resolver(json)
214
+ }
215
+ }
216
+
217
+ @objc(createComment:content:authToken:parentId:resolver:rejecter:)
218
+ func createComment(_ postId: String, content: String, authToken: String, parentId: String?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
219
+ SmartLinksBridgeAPI.createComment(
220
+ postId: postId,
221
+ content: content,
222
+ authToken: authToken,
223
+ parentId: parentId,
224
+ completion: { json in resolver(json) }
225
+ )
226
+ }
227
+
228
+ @objc(toggleCommentLike:authToken:resolver:rejecter:)
229
+ func toggleCommentLike(_ commentId: String, authToken: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
230
+ SmartLinksBridgeAPI.toggleCommentLike(commentId: commentId, authToken: authToken) { json in
231
+ resolver(json)
232
+ }
233
+ }
234
+
235
+ @objc(fetchActiveNotificationAd:language:isDebug:resolver:rejecter:)
236
+ func fetchActiveNotificationAd(_ appId: NSNumber?, language: String?, isDebug: Bool, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
237
+ SmartLinksBridgeAPI.fetchActiveNotificationAd(
238
+ appId: appId?.intValue,
239
+ language: language,
240
+ isDebug: isDebug,
241
+ completion: { json in resolver(json) }
242
+ )
243
+ }
244
+
245
+ @objc(registerDevice:platform:deviceType:appVersion:language:resolver:rejecter:)
246
+ func registerDevice(_ fcmToken: String, platform: String?, deviceType: String?, appVersion: String?, language: String?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
247
+ SmartLinksBridgeAPI.registerDevice(
248
+ fcmToken: fcmToken,
249
+ platform: platform,
250
+ deviceType: deviceType,
251
+ appVersion: appVersion,
252
+ language: language,
253
+ completion: { json in resolver(json) }
254
+ )
255
+ }
256
+
257
+ @objc(trackNotificationAdImpression:resolver:rejecter:)
258
+ func trackNotificationAdImpression(_ adId: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
259
+ SmartLinksBridgeAPI.trackNotificationAdImpression(adId: adId.intValue) { json in
260
+ resolver(json)
261
+ }
262
+ }
263
+
264
+ @objc(trackNotificationAdClick:resolver:rejecter:)
265
+ func trackNotificationAdClick(_ adId: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
266
+ SmartLinksBridgeAPI.trackNotificationAdClick(adId: adId.intValue) { json in
267
+ resolver(json)
268
+ }
269
+ }
270
+
271
+ private func emitDeepLink(_ route: DeepLinkRoute) {
272
+ let payload: [String: Any] = [
273
+ "route": route.route,
274
+ "params": route.parameters,
275
+ "link": route.link ?? "",
276
+ "appSlug": route.appSlug ?? "",
277
+ "is_first_launch": route.isFirstLaunch,
278
+ ]
279
+ sendEvent(withName: "SmartLinksDeepLink", body: payload)
280
+ }
281
+ }
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "react-native-smartlinks",
3
+ "version": "2.0.0",
4
+ "description": "Native bridge for SmartLinks analytics and deep links on React Native",
5
+ "main": "src/index.ts",
6
+ "types": "src/index.ts",
7
+ "react-native": "src/index.ts",
8
+ "files": [
9
+ "src",
10
+ "android/src",
11
+ "android/build.gradle",
12
+ "ios",
13
+ "react-native-smartlinks.podspec",
14
+ "react-native.config.js",
15
+ "!.npmignore"
16
+ ],
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "peerDependencies": {
21
+ "react": "*",
22
+ "react-native": "*"
23
+ },
24
+ "devDependencies": {
25
+ "react": "^18.3.1",
26
+ "react-native": "^0.76.6",
27
+ "typescript": "^5.7.3"
28
+ },
29
+ "keywords": [
30
+ "smartlinks",
31
+ "react-native",
32
+ "analytics",
33
+ "deep-linking"
34
+ ],
35
+ "license": "Apache-2.0",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://gitlab.com/elmansoryanas/smartlinks-react-native.git",
39
+ "directory": "packages/native"
40
+ }
41
+ }
@@ -0,0 +1,27 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'react-native-smartlinks'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.license = 'Apache-2.0'
10
+ s.homepage = package['repository']['url']
11
+ s.authors = { 'SmartLinks' => 'support@smartlinks.live' }
12
+ s.platforms = { :ios => '15.0' }
13
+ s.source = {
14
+ :git => 'https://gitlab.com/elmansoryanas/smartlinks-react-native.git',
15
+ :tag => "v#{s.version}"
16
+ }
17
+
18
+ s.source_files = 'ios/*.{h,m,mm,swift}'
19
+ s.resource_bundles = {
20
+ 'react_native_smartlinks_Privacy' => ['ios/PrivacyInfo.xcprivacy']
21
+ }
22
+
23
+ s.dependency 'React-Core'
24
+ # Published from https://gitlab.com/elmansoryanas/smartlinks_ios
25
+ s.dependency 'SmartLinksSDK/Core', '~> 2.0.1'
26
+ s.swift_version = '5.9'
27
+ end
@@ -0,0 +1,12 @@
1
+ module.exports = {
2
+ dependency: {
3
+ platforms: {
4
+ android: {
5
+ sourceDir: './android',
6
+ packageImportPath: 'import live.smartlinks.reactnative.SmartLinksPackage;',
7
+ packageInstance: 'new SmartLinksPackage()',
8
+ },
9
+ ios: {},
10
+ },
11
+ },
12
+ };
package/src/index.ts ADDED
@@ -0,0 +1,84 @@
1
+ import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
2
+
3
+ export type DeepLinkRoute = {
4
+ route: string;
5
+ params: Record<string, string>;
6
+ link?: string;
7
+ appSlug?: string;
8
+ is_first_launch?: boolean;
9
+ };
10
+
11
+ type NativeSmartLinks = {
12
+ initialize(apiKey: string, debugMode: boolean): Promise<boolean>;
13
+ getAppUserId(): Promise<string | null>;
14
+ sendEvent(eventName: string, params: Record<string, unknown>): Promise<void>;
15
+ generateLink(
16
+ route: string,
17
+ params: Record<string, unknown>,
18
+ shortLink: boolean,
19
+ ): Promise<string | null>;
20
+ registerLinkListener(): Promise<void>;
21
+ };
22
+
23
+ const LINKING = NativeModules.SmartLinks as NativeSmartLinks | undefined;
24
+
25
+ const emitter = LINKING ? new NativeEventEmitter(NativeModules.SmartLinks) : null;
26
+
27
+ export async function nativeInitialize(
28
+ apiKey: string,
29
+ debugMode = false,
30
+ ): Promise<boolean> {
31
+ if (!LINKING) {
32
+ if (__DEV__) {
33
+ console.warn('[SmartLinks] Native module unavailable');
34
+ }
35
+ return false;
36
+ }
37
+ return LINKING.initialize(apiKey, debugMode);
38
+ }
39
+
40
+ export async function nativeGetAppUserId(): Promise<string | null> {
41
+ if (!LINKING) return null;
42
+ return LINKING.getAppUserId();
43
+ }
44
+
45
+ export async function nativeSendEvent(
46
+ eventName: string,
47
+ params: Record<string, unknown> = {},
48
+ ): Promise<void> {
49
+ if (!LINKING) return;
50
+ await LINKING.sendEvent(eventName, params);
51
+ }
52
+
53
+ export async function nativeGenerateLink(
54
+ route: string,
55
+ params: Record<string, unknown> = {},
56
+ shortLink = true,
57
+ ): Promise<string | null> {
58
+ if (!LINKING) return null;
59
+ return LINKING.generateLink(route, params, shortLink);
60
+ }
61
+
62
+ export function addDeepLinkListener(
63
+ listener: (route: DeepLinkRoute) => void,
64
+ ): () => void {
65
+ if (!emitter || !LINKING) {
66
+ return () => undefined;
67
+ }
68
+
69
+ const subscription = emitter.addListener('SmartLinksDeepLink', (payload) => {
70
+ listener({
71
+ route: payload.route ?? '',
72
+ params: payload.params ?? {},
73
+ link: payload.link,
74
+ appSlug: payload.appSlug ?? payload.app_slug,
75
+ is_first_launch: payload.is_first_launch,
76
+ });
77
+ });
78
+
79
+ void LINKING.registerLinkListener();
80
+
81
+ return () => subscription.remove();
82
+ }
83
+
84
+ export const isNativeAvailable = Platform.OS === 'android' || Platform.OS === 'ios';