lig-scanner-expo-sdk 1.0.0 → 1.0.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/android/.gradle/9.0.0/checksums/checksums.lock +0 -0
- package/android/.gradle/9.0.0/fileChanges/last-build.bin +0 -0
- package/android/.gradle/9.0.0/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/9.0.0/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -2
- package/android/build.gradle +3 -3
- package/android/src/main/AndroidManifest.xml +2 -1
- package/android/src/main/java/tw/com/lig/scanner/rn/expo/ARPlayerView.kt +188 -140
- package/android/src/main/java/tw/com/lig/scanner/rn/expo/LigScannerExpoSdkModule.kt +50 -12
- package/build/LigScannerExpoSdk.types.d.ts +1 -1
- package/build/LigScannerExpoSdk.types.d.ts.map +1 -1
- package/build/LigScannerExpoSdk.types.js.map +1 -1
- package/build/ScanView.js +3 -3
- package/build/ScanView.js.map +1 -1
- package/build/hooks/useLigScanner.d.ts +13 -52
- package/build/hooks/useLigScanner.d.ts.map +1 -1
- package/build/hooks/useLigScanner.js +36 -39
- package/build/hooks/useLigScanner.js.map +1 -1
- package/lig-scanner-sample-app/App.tsx +287 -0
- package/lig-scanner-sample-app/README.md +53 -0
- package/lig-scanner-sample-app/app.json +44 -0
- package/lig-scanner-sample-app/assets/adaptive-icon.png +0 -0
- package/lig-scanner-sample-app/assets/favicon.png +0 -0
- package/lig-scanner-sample-app/assets/icon.png +0 -0
- package/lig-scanner-sample-app/assets/splash-icon.png +0 -0
- package/lig-scanner-sample-app/babel.config.js +6 -0
- package/lig-scanner-sample-app/index.ts +8 -0
- package/lig-scanner-sample-app/package-lock.json +8177 -0
- package/lig-scanner-sample-app/package.json +25 -0
- package/lig-scanner-sample-app/tsconfig.json +6 -0
- package/package.json +1 -1
- package/src/LigScannerExpoSdk.types.ts +4 -4
- package/src/ScanView.tsx +6 -6
- package/src/hooks/useLigScanner.ts +60 -67
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
#Sat
|
|
2
|
-
gradle.version=
|
|
1
|
+
#Sat Jan 10 13:13:23 CST 2026
|
|
2
|
+
gradle.version=9.0.0
|
package/android/build.gradle
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
apply plugin: 'com.android.library'
|
|
2
2
|
|
|
3
3
|
group = 'tw.com.lig.scanner.rn.expo'
|
|
4
|
-
version = '0.
|
|
4
|
+
version = '1.0.1'
|
|
5
5
|
|
|
6
6
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
7
7
|
apply from: expoModulesCorePlugin
|
|
@@ -46,7 +46,7 @@ android {
|
|
|
46
46
|
namespace "tw.com.lig.scanner.rn.expo"
|
|
47
47
|
defaultConfig {
|
|
48
48
|
versionCode 1
|
|
49
|
-
versionName "0.
|
|
49
|
+
versionName "1.0.1"
|
|
50
50
|
}
|
|
51
51
|
lintOptions {
|
|
52
52
|
abortOnError false
|
|
@@ -55,7 +55,7 @@ android {
|
|
|
55
55
|
|
|
56
56
|
dependencies {
|
|
57
57
|
// LiG Scanner and Player SDK dependencies - using known working versions
|
|
58
|
-
implementation 'tw.com.lig:scanner:9.
|
|
58
|
+
implementation 'tw.com.lig:scanner:9.7.2'
|
|
59
59
|
implementation 'tw.com.lig:player:1.7.9'
|
|
60
60
|
|
|
61
61
|
// ARCore dependency
|
|
@@ -2,36 +2,33 @@ package tw.com.lig.scanner.rn.expo
|
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.widget.FrameLayout
|
|
5
|
-
import
|
|
5
|
+
import com.google.ar.core.Config
|
|
6
|
+
import com.google.ar.core.Session
|
|
7
|
+
import com.google.ar.sceneform.ArSceneView
|
|
8
|
+
import com.google.ar.sceneform.math.Matrix
|
|
6
9
|
import expo.modules.kotlin.AppContext
|
|
7
10
|
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
8
11
|
import expo.modules.kotlin.views.ExpoView
|
|
9
|
-
import com.google.ar.sceneform.ArSceneView
|
|
10
|
-
import com.google.ar.core.Config
|
|
11
|
-
import com.google.ar.core.Session
|
|
12
|
-
import kotlinx.coroutines.CoroutineScope
|
|
13
|
-
import kotlinx.coroutines.Dispatchers
|
|
14
|
-
import kotlinx.coroutines.launch
|
|
15
12
|
import kotlinx.coroutines.MainScope
|
|
16
13
|
import kotlinx.coroutines.cancel
|
|
14
|
+
import kotlinx.coroutines.launch
|
|
15
|
+
import tw.com.lig.sdk.player.LiGCoordinateSystem
|
|
17
16
|
import tw.com.lig.sdk.player.LiGPlayer
|
|
18
17
|
import tw.com.lig.sdk.player.model.Game
|
|
18
|
+
import tw.com.lig.sdk.scanner.LigTag
|
|
19
19
|
import tw.com.lig.sdk.scanner.Transform
|
|
20
20
|
import tw.com.lig.sdk.scanner.Vector3
|
|
21
|
-
import tw.com.lig.sdk.scanner.LigTag
|
|
22
|
-
import tw.com.lig.sdk.player.LiGCoordinateSystem
|
|
23
|
-
import com.google.ar.sceneform.math.Matrix
|
|
24
21
|
|
|
25
22
|
class ARPlayerView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
26
23
|
companion object {
|
|
27
24
|
private const val TAG = "ARPlayerView"
|
|
28
25
|
}
|
|
29
|
-
|
|
26
|
+
|
|
30
27
|
private val onSceneLoaded by EventDispatcher()
|
|
31
28
|
private val onActionTriggered by EventDispatcher()
|
|
32
29
|
private val onNavigationUpdate by EventDispatcher()
|
|
33
30
|
private val onError by EventDispatcher()
|
|
34
|
-
|
|
31
|
+
|
|
35
32
|
private var arSceneView: ArSceneView? = null
|
|
36
33
|
private var currentSceneId: String? = null
|
|
37
34
|
private var autoLoad: Boolean = true
|
|
@@ -41,138 +38,151 @@ class ARPlayerView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
41
38
|
private var ligTagTransform: List<Double>? = null
|
|
42
39
|
private var isArOriginSet = false
|
|
43
40
|
private val mainScope = MainScope()
|
|
44
|
-
|
|
41
|
+
|
|
45
42
|
init {
|
|
46
43
|
// Initialize the AR view container
|
|
47
|
-
layoutParams =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
layoutParams =
|
|
45
|
+
FrameLayout.LayoutParams(
|
|
46
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
47
|
+
FrameLayout.LayoutParams.MATCH_PARENT
|
|
48
|
+
)
|
|
51
49
|
}
|
|
52
|
-
|
|
50
|
+
|
|
53
51
|
fun initialize() {
|
|
54
52
|
if (arSceneView == null) {
|
|
55
53
|
val activity = appContext.activityProvider?.currentActivity ?: return
|
|
56
|
-
|
|
54
|
+
|
|
57
55
|
try {
|
|
58
56
|
// Create AR scene view
|
|
59
|
-
arSceneView =
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
57
|
+
arSceneView =
|
|
58
|
+
ArSceneView(context).apply {
|
|
59
|
+
layoutParams =
|
|
60
|
+
FrameLayout.LayoutParams(
|
|
61
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
62
|
+
FrameLayout.LayoutParams.MATCH_PARENT
|
|
63
|
+
)
|
|
64
|
+
setBackgroundColor(android.graphics.Color.TRANSPARENT)
|
|
65
|
+
|
|
66
|
+
// Disable plane renderer
|
|
67
|
+
planeRenderer?.isVisible = false
|
|
68
|
+
scene?.camera?.nearClipPlane = 0.001f
|
|
69
|
+
scene?.camera?.farClipPlane = 100f
|
|
70
|
+
}
|
|
71
71
|
addView(arSceneView)
|
|
72
|
-
|
|
72
|
+
|
|
73
73
|
// Configure AR session
|
|
74
74
|
val session = Session(activity)
|
|
75
|
-
val config =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
75
|
+
val config =
|
|
76
|
+
Config(session).apply {
|
|
77
|
+
focusMode = Config.FocusMode.AUTO
|
|
78
|
+
augmentedFaceMode = Config.AugmentedFaceMode.DISABLED
|
|
79
|
+
cloudAnchorMode = Config.CloudAnchorMode.DISABLED
|
|
80
|
+
updateMode = Config.UpdateMode.LATEST_CAMERA_IMAGE
|
|
81
|
+
lightEstimationMode = Config.LightEstimationMode.DISABLED
|
|
82
|
+
depthMode = Config.DepthMode.DISABLED
|
|
83
|
+
planeFindingMode = Config.PlaneFindingMode.DISABLED
|
|
84
|
+
}
|
|
84
85
|
session.configure(config)
|
|
85
86
|
arSceneView?.session = session
|
|
86
|
-
|
|
87
|
+
|
|
87
88
|
// Configure Player SDK
|
|
88
89
|
LiGPlayer.context.configureSceneView(arSceneView!!)
|
|
89
|
-
|
|
90
|
+
|
|
90
91
|
// Set up listeners
|
|
91
92
|
setupPlayerListeners()
|
|
92
|
-
|
|
93
|
+
|
|
93
94
|
// Setup AR coordinate system if data is available
|
|
94
95
|
setupArOriginIfReady()
|
|
95
96
|
} catch (e: Exception) {
|
|
96
97
|
// Handle initialization error
|
|
97
|
-
onError(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
onError(
|
|
99
|
+
mapOf(
|
|
100
|
+
"code" to "INIT_ERROR",
|
|
101
|
+
"message" to (e.message ?: "Failed to initialize AR Player")
|
|
102
|
+
)
|
|
103
|
+
)
|
|
101
104
|
}
|
|
102
105
|
}
|
|
103
106
|
}
|
|
104
|
-
|
|
107
|
+
|
|
105
108
|
private fun setupPlayerListeners() {
|
|
106
109
|
LiGPlayer.context.onSceneLoaded = {
|
|
107
110
|
val ligScene = LiGPlayer.context.ligScene
|
|
108
|
-
onSceneLoaded(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
handleGameEvent(game)
|
|
111
|
+
onSceneLoaded(
|
|
112
|
+
mapOf(
|
|
113
|
+
"scene" to
|
|
114
|
+
mapOf(
|
|
115
|
+
"id" to (ligScene?.scene?.sceneID?.toString() ?: ""),
|
|
116
|
+
"name" to (ligScene?.scene?.name ?: ""),
|
|
117
|
+
"status" to "loaded"
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
)
|
|
119
121
|
}
|
|
120
|
-
|
|
122
|
+
|
|
123
|
+
LiGPlayer.context.gameListener = { game -> handleGameEvent(game) }
|
|
124
|
+
|
|
121
125
|
LiGPlayer.context.actionListener = { node, actionModel ->
|
|
122
|
-
onActionTriggered(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
onActionTriggered(
|
|
127
|
+
mapOf(
|
|
128
|
+
"action" to
|
|
129
|
+
mapOf(
|
|
130
|
+
"id" to (actionModel.action.id?.toString() ?: ""),
|
|
131
|
+
"type" to (actionModel.action.id?.toString() ?: "")
|
|
132
|
+
)
|
|
133
|
+
)
|
|
134
|
+
)
|
|
128
135
|
}
|
|
129
|
-
|
|
136
|
+
|
|
130
137
|
LiGPlayer.context.onPositionChanged = { progress, isCompleted ->
|
|
131
|
-
onNavigationUpdate(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
138
|
+
onNavigationUpdate(
|
|
139
|
+
mapOf(
|
|
140
|
+
"navigation" to
|
|
141
|
+
mapOf(
|
|
142
|
+
"progress" to progress.toDouble(),
|
|
143
|
+
"isCompleted" to isCompleted
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
)
|
|
137
147
|
}
|
|
138
148
|
}
|
|
139
|
-
|
|
149
|
+
|
|
140
150
|
fun setSceneId(sceneId: String?) {
|
|
141
151
|
currentSceneId = sceneId
|
|
142
152
|
if (autoLoad && sceneId != null) {
|
|
143
153
|
loadScene(sceneId)
|
|
144
154
|
}
|
|
145
155
|
}
|
|
146
|
-
|
|
156
|
+
|
|
147
157
|
fun setLightTagId(tagId: String?) {
|
|
148
158
|
this.lightTagId = tagId
|
|
149
159
|
}
|
|
150
|
-
|
|
160
|
+
|
|
151
161
|
fun setAutoLoad(autoLoad: Boolean) {
|
|
152
162
|
this.autoLoad = autoLoad
|
|
153
163
|
}
|
|
154
|
-
|
|
164
|
+
|
|
155
165
|
fun setScannerAccessToken(token: String?) {
|
|
156
166
|
if (token != null) {
|
|
157
167
|
LiGPlayer.context.accessToken = token
|
|
158
168
|
}
|
|
159
169
|
}
|
|
160
|
-
|
|
170
|
+
|
|
161
171
|
fun setRotation(rotation: Map<String, Double>?) {
|
|
162
172
|
this.rotation = rotation
|
|
163
173
|
setupArOriginIfReady()
|
|
164
174
|
}
|
|
165
|
-
|
|
175
|
+
|
|
166
176
|
fun setTranslation(translation: Map<String, Double>?) {
|
|
167
177
|
this.translation = translation
|
|
168
178
|
setupArOriginIfReady()
|
|
169
179
|
}
|
|
170
|
-
|
|
180
|
+
|
|
171
181
|
fun setLigTagTransform(transform: List<Double>?) {
|
|
172
182
|
this.ligTagTransform = transform
|
|
173
183
|
// Store ligTagTransform
|
|
174
184
|
}
|
|
175
|
-
|
|
185
|
+
|
|
176
186
|
fun loadScene(sceneId: String) {
|
|
177
187
|
mainScope.launch {
|
|
178
188
|
try {
|
|
@@ -183,101 +193,139 @@ class ARPlayerView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
183
193
|
LiGPlayer.context.load(context)
|
|
184
194
|
}
|
|
185
195
|
} catch (e: Exception) {
|
|
186
|
-
onError(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
196
|
+
onError(
|
|
197
|
+
mapOf(
|
|
198
|
+
"code" to "SCENE_LOAD_ERROR",
|
|
199
|
+
"message" to (e.message ?: "Failed to load scene")
|
|
200
|
+
)
|
|
201
|
+
)
|
|
190
202
|
}
|
|
191
203
|
}
|
|
192
204
|
}
|
|
193
|
-
|
|
205
|
+
|
|
194
206
|
fun unloadScene() {
|
|
195
207
|
LiGPlayer.context.unload()
|
|
196
208
|
}
|
|
197
|
-
|
|
209
|
+
|
|
198
210
|
private fun handleGameEvent(game: Game) {
|
|
199
|
-
onActionTriggered(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
211
|
+
onActionTriggered(
|
|
212
|
+
mapOf(
|
|
213
|
+
"action" to
|
|
214
|
+
mapOf(
|
|
215
|
+
"id" to "game_${game.gameId}",
|
|
216
|
+
"type" to "game",
|
|
217
|
+
"params" to
|
|
218
|
+
mapOf(
|
|
219
|
+
"gameId" to game.gameId,
|
|
220
|
+
"status" to (game.data?.action_name ?: ""),
|
|
221
|
+
"coins" to (game.data?.coinQuantity ?: 0)
|
|
222
|
+
)
|
|
223
|
+
)
|
|
207
224
|
)
|
|
208
|
-
|
|
209
|
-
))
|
|
225
|
+
)
|
|
210
226
|
}
|
|
227
|
+
|
|
228
|
+
private var isUpdateListenerAttached = false
|
|
211
229
|
|
|
212
230
|
private fun setupArOriginIfReady() {
|
|
213
231
|
// Only setup once and when we have all required data
|
|
214
|
-
if (isArOriginSet ||
|
|
232
|
+
if (isArOriginSet ||
|
|
233
|
+
rotation == null ||
|
|
234
|
+
translation == null ||
|
|
235
|
+
lightTagId == null ||
|
|
236
|
+
arSceneView == null
|
|
237
|
+
) {
|
|
215
238
|
return
|
|
216
239
|
}
|
|
217
|
-
|
|
240
|
+
|
|
241
|
+
// Check if AR frame is valid and tracking
|
|
242
|
+
val frame = arSceneView?.arFrame
|
|
243
|
+
if (frame == null || frame.camera.trackingState != com.google.ar.core.TrackingState.TRACKING) {
|
|
244
|
+
if (!isUpdateListenerAttached && arSceneView?.scene != null) {
|
|
245
|
+
arSceneView?.scene?.addOnUpdateListener(updateListener)
|
|
246
|
+
isUpdateListenerAttached = true
|
|
247
|
+
}
|
|
248
|
+
return
|
|
249
|
+
}
|
|
250
|
+
|
|
218
251
|
try {
|
|
219
|
-
//
|
|
220
|
-
|
|
221
|
-
|
|
252
|
+
// Remove listener if we are proceeding
|
|
253
|
+
if (isUpdateListenerAttached) {
|
|
254
|
+
arSceneView?.scene?.removeOnUpdateListener(updateListener)
|
|
255
|
+
isUpdateListenerAttached = false
|
|
256
|
+
}
|
|
222
257
|
|
|
258
|
+
// Get current camera pose from AR session
|
|
259
|
+
val cameraPoseData = FloatArray(16)
|
|
260
|
+
frame.camera.displayOrientedPose.toMatrix(cameraPoseData, 0)
|
|
261
|
+
val cameraPose = Transform(cameraPoseData)
|
|
262
|
+
|
|
223
263
|
// Create Vector3 objects from the coordinate data
|
|
224
|
-
val rotationVec =
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
264
|
+
val rotationVec =
|
|
265
|
+
Vector3(
|
|
266
|
+
rotation!!["x"]!!.toFloat(),
|
|
267
|
+
rotation!!["y"]!!.toFloat(),
|
|
268
|
+
rotation!!["z"]!!.toFloat()
|
|
269
|
+
)
|
|
270
|
+
val translationVec =
|
|
271
|
+
Vector3(
|
|
272
|
+
translation!!["x"]!!.toFloat(),
|
|
273
|
+
translation!!["y"]!!.toFloat(),
|
|
274
|
+
translation!!["z"]!!.toFloat()
|
|
275
|
+
)
|
|
276
|
+
|
|
235
277
|
// Create a temporary LigTag object to use its proper transform method
|
|
236
278
|
// This uses the real LiG SDK coordinate transformation mathematics
|
|
237
|
-
val tempLigTag =
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
279
|
+
val tempLigTag =
|
|
280
|
+
LigTag(
|
|
281
|
+
deviceId = lightTagId!!.toLong(),
|
|
282
|
+
coordinateX = 0.5f, // Center of screen (not used for transformation)
|
|
283
|
+
coordinateY = 0.5f,
|
|
284
|
+
ready = true,
|
|
285
|
+
rx = rotationVec.x,
|
|
286
|
+
ry = rotationVec.y,
|
|
287
|
+
rz = rotationVec.z,
|
|
288
|
+
tx = translationVec.x,
|
|
289
|
+
ty = translationVec.y,
|
|
290
|
+
tz = translationVec.z
|
|
291
|
+
)
|
|
292
|
+
|
|
250
293
|
// Use the real LiG SDK transformation: ligTag.transform(cameraPose)
|
|
251
294
|
val worldTransform = tempLigTag.transform(cameraPose)
|
|
252
|
-
|
|
295
|
+
|
|
253
296
|
// Set world origin using LiG coordinate system
|
|
254
297
|
val deviceIdLong = lightTagId!!.toLongOrNull() ?: return
|
|
255
298
|
LiGCoordinateSystem.getLightTagTransform(
|
|
256
|
-
|
|
257
|
-
|
|
299
|
+
deviceIdLong,
|
|
300
|
+
Matrix(worldTransform.toMatrix())
|
|
258
301
|
) { position, rotation ->
|
|
259
302
|
mainScope.launch {
|
|
260
303
|
val anchor = LiGPlayer.context.origin
|
|
261
304
|
anchor.worldPosition = position
|
|
262
305
|
anchor.worldRotation = rotation
|
|
263
306
|
arSceneView?.scene?.addChild(anchor)
|
|
264
|
-
|
|
307
|
+
|
|
265
308
|
isArOriginSet = true
|
|
266
|
-
|
|
309
|
+
|
|
267
310
|
// Now load the AR scene content
|
|
268
311
|
loadArContent(deviceIdLong)
|
|
269
312
|
}
|
|
270
313
|
}
|
|
271
314
|
} catch (e: Exception) {
|
|
272
315
|
// Handle AR origin setup error
|
|
273
|
-
onError(
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
316
|
+
onError(
|
|
317
|
+
mapOf(
|
|
318
|
+
"code" to "AR_ORIGIN_ERROR",
|
|
319
|
+
"message" to (e.message ?: "Failed to setup AR coordinate system")
|
|
320
|
+
)
|
|
321
|
+
)
|
|
277
322
|
}
|
|
278
323
|
}
|
|
279
324
|
|
|
280
|
-
|
|
325
|
+
private val updateListener = com.google.ar.sceneform.Scene.OnUpdateListener {
|
|
326
|
+
if (!isArOriginSet) setupArOriginIfReady()
|
|
327
|
+
}
|
|
328
|
+
|
|
281
329
|
private fun loadArContent(deviceId: Long) {
|
|
282
330
|
LiGPlayer.context.load(deviceId, null) { coordinateSystem ->
|
|
283
331
|
coordinateSystem?.let { cs ->
|
|
@@ -288,13 +336,13 @@ class ARPlayerView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
288
336
|
}
|
|
289
337
|
}
|
|
290
338
|
}
|
|
291
|
-
|
|
339
|
+
|
|
292
340
|
override fun onAttachedToWindow() {
|
|
293
341
|
super.onAttachedToWindow()
|
|
294
342
|
initialize()
|
|
295
343
|
arSceneView?.resume()
|
|
296
344
|
}
|
|
297
|
-
|
|
345
|
+
|
|
298
346
|
override fun onDetachedFromWindow() {
|
|
299
347
|
super.onDetachedFromWindow()
|
|
300
348
|
arSceneView?.pause()
|
|
@@ -303,4 +351,4 @@ class ARPlayerView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
303
351
|
arSceneView?.destroy()
|
|
304
352
|
arSceneView = null
|
|
305
353
|
}
|
|
306
|
-
}
|
|
354
|
+
}
|
|
@@ -5,9 +5,14 @@ import expo.modules.kotlin.modules.ModuleDefinition
|
|
|
5
5
|
import expo.modules.kotlin.Promise
|
|
6
6
|
import tw.com.lig.sdk.scanner.LiGScanner
|
|
7
7
|
import tw.com.lig.sdk.scanner.LigTag
|
|
8
|
-
import android.util.Log
|
|
9
8
|
import android.content.Intent
|
|
10
9
|
|
|
10
|
+
import android.Manifest
|
|
11
|
+
import android.content.pm.PackageManager
|
|
12
|
+
import androidx.core.content.ContextCompat
|
|
13
|
+
import androidx.core.app.ActivityCompat
|
|
14
|
+
import expo.modules.core.interfaces.ActivityProvider
|
|
15
|
+
|
|
11
16
|
class LigScannerExpoSdkModule : Module() {
|
|
12
17
|
private var lastDetectedTag: LigTag? = null
|
|
13
18
|
|
|
@@ -23,6 +28,42 @@ class LigScannerExpoSdkModule : Module() {
|
|
|
23
28
|
// Real LiG Scanner SDK Events (matching reference project)
|
|
24
29
|
Events("onLigtagFound", "onStatusReported", "onARReady", "onARError", "onARClosed", "onGameEvent")
|
|
25
30
|
|
|
31
|
+
AsyncFunction("requestCameraPermissions") { promise: Promise ->
|
|
32
|
+
val activity = appContext.activityProvider?.currentActivity
|
|
33
|
+
val context = appContext.reactContext
|
|
34
|
+
|
|
35
|
+
if (activity == null || context == null) {
|
|
36
|
+
promise.reject("ERR_NO_ACTIVITY", "No activity found", null)
|
|
37
|
+
return@AsyncFunction
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
|
|
41
|
+
promise.resolve(mapOf(
|
|
42
|
+
"status" to "granted",
|
|
43
|
+
"granted" to true
|
|
44
|
+
))
|
|
45
|
+
return@AsyncFunction
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// We cannot easily use ActivityCompat.requestPermissions here because we can't reliably catch onRequestPermissionsResult
|
|
49
|
+
// in a simple Expo module without valid ActivityEventListener hook which Expo modules simplify differently.
|
|
50
|
+
// However, Expo uses `Permissions` module typically. Since we are in bare workflow/vanilla android context of module:
|
|
51
|
+
|
|
52
|
+
// Simpler approach compatible with most Expo apps:
|
|
53
|
+
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.CAMERA), 1001)
|
|
54
|
+
|
|
55
|
+
// NOTE: This basic implementation returns "undetermined" immediately because requestPermissions is async
|
|
56
|
+
// and we don't have the listener hooked up in this simple snippet.
|
|
57
|
+
// Ideally we'd use the Expo Permissions interface, but we are hacking this to avoid deps.
|
|
58
|
+
// For immediate unblocking:
|
|
59
|
+
|
|
60
|
+
promise.resolve(mapOf(
|
|
61
|
+
"status" to "undetermined", // Or "requesting" - Client side should assume it popped up
|
|
62
|
+
"granted" to false
|
|
63
|
+
))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Real LiG Scanner SDK Methods (copied from reference project)
|
|
26
67
|
// Real LiG Scanner SDK Methods (copied from reference project)
|
|
27
68
|
AsyncFunction("initialize") { productKey: String, promise: Promise ->
|
|
28
69
|
try {
|
|
@@ -44,15 +85,15 @@ class LigScannerExpoSdkModule : Module() {
|
|
|
44
85
|
"x" to ligtag.coordinateX.toDouble(),
|
|
45
86
|
"y" to ligtag.coordinateY.toDouble(),
|
|
46
87
|
"isReady" to ligtag.isReady,
|
|
47
|
-
"
|
|
88
|
+
"detected" to ligtag.detected,
|
|
48
89
|
"deviceId" to ligtag.deviceId.toInt(),
|
|
49
|
-
"status" to
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
90
|
+
"status" to if (ligtag.isReady) "READY"
|
|
91
|
+
else if (ligtag.decoded) "DECODED"
|
|
92
|
+
else if (ligtag.detected) "DETECTED"
|
|
93
|
+
else "NOT_DETECTED"
|
|
53
94
|
)
|
|
54
95
|
|
|
55
|
-
if (ligtag.
|
|
96
|
+
if (ligtag.detected) {
|
|
56
97
|
params["detectionTime"] = ligtag.detectionTime.toInt()
|
|
57
98
|
params["decodedTime"] = ligtag.decodedTime.toInt()
|
|
58
99
|
}
|
|
@@ -68,11 +109,8 @@ class LigScannerExpoSdkModule : Module() {
|
|
|
68
109
|
"y" to ligtag.translation.y.toDouble(),
|
|
69
110
|
"z" to ligtag.translation.z.toDouble()
|
|
70
111
|
)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"y" to ligtag.position.y.toDouble(),
|
|
74
|
-
"z" to ligtag.position.z.toDouble()
|
|
75
|
-
)
|
|
112
|
+
// Valid 6DOF pose is available
|
|
113
|
+
params["validPose"] = true
|
|
76
114
|
// Add accessToken for AR cloud authentication
|
|
77
115
|
params["accessToken"] = ligtag.accessToken
|
|
78
116
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LigScannerExpoSdk.types.d.ts","sourceRoot":"","sources":["../src/LigScannerExpoSdk.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzD,MAAM,MAAM,6BAA6B,GAAG;IAC1C,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,gBAAgB,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACxD,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,EAAE,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/C,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,EAAE,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,KAAK,IAAI,CAAC;CAC7D,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF,MAAM,MAAM,OAAO,GAAG;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG;IACjC,QAAQ,EAAE,UAAU,CAAC;IACrB,SAAS,IAAI,UAAU,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,UAAU,CAAC;IACrB,QAAQ,IAAI,MAAM,EAAE,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,OAAO,EAAE,OAAO,CAAC;IACjB,
|
|
1
|
+
{"version":3,"file":"LigScannerExpoSdk.types.d.ts","sourceRoot":"","sources":["../src/LigScannerExpoSdk.types.ts"],"names":[],"mappings":"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"}
|