298 lines
8.1 KiB
JavaScript
298 lines
8.1 KiB
JavaScript
const { withDangerousMod } = require("@expo/config-plugins");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
|
|
// const packageName = "net.alpla.lst.mobile";
|
|
// const packagePath = "com/alpla/lst/mobile";
|
|
const packageName = "net.alpla.lst.mobile";
|
|
const packagePath = "net/alpla/lst/mobile";
|
|
// const packageName = config.android?.package;
|
|
// const packagePath = packageName.replace(/\./g, "/");
|
|
|
|
const moduleCode = `package ${packageName}.scanner
|
|
|
|
import android.content.BroadcastReceiver
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.content.IntentFilter
|
|
import android.os.Bundle
|
|
import com.facebook.react.bridge.*
|
|
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
|
|
class ZebraScannerModule(
|
|
private val reactContext: ReactApplicationContext
|
|
) : ReactContextBaseJavaModule(reactContext) {
|
|
|
|
override fun getName(): String = "ZebraScanner"
|
|
|
|
private val scanAction = "com.lst.mobile.SCAN"
|
|
private var receiverRegistered = false
|
|
|
|
private val scanReceiver = object : BroadcastReceiver() {
|
|
override fun onReceive(context: Context?, intent: Intent?) {
|
|
println("LST SCANNER: received intent -> \${intent?.action}")
|
|
|
|
if (intent?.action != scanAction) {
|
|
println("LST SCANNER: wrong action")
|
|
return
|
|
}
|
|
|
|
val barcodeData: String? =
|
|
intent.getStringExtra("com.symbol.datawedge.data_string")
|
|
|
|
val labelType: String? =
|
|
intent.getStringExtra("com.symbol.datawedge.label_type")
|
|
|
|
val source: String? =
|
|
intent.getStringExtra("com.symbol.datawedge.source")
|
|
|
|
println("LST SCANNER: data=\$barcodeData label=\$labelType source=\$source")
|
|
|
|
if (barcodeData.isNullOrBlank()) {
|
|
println("LST SCANNER: empty barcode")
|
|
return
|
|
}
|
|
|
|
val payload = Arguments.createMap().apply {
|
|
putString("data", barcodeData)
|
|
putString("labelType", labelType)
|
|
putString("source", source)
|
|
putDouble("timestamp", System.currentTimeMillis().toDouble())
|
|
}
|
|
|
|
sendEvent("barcodeScanned", payload)
|
|
}
|
|
}
|
|
|
|
@ReactMethod
|
|
fun startListening() {
|
|
if (receiverRegistered) return
|
|
|
|
reactContext.registerReceiver(
|
|
scanReceiver,
|
|
IntentFilter(scanAction),
|
|
Context.RECEIVER_EXPORTED
|
|
)
|
|
|
|
receiverRegistered = true
|
|
}
|
|
|
|
@ReactMethod
|
|
fun stopListening() {
|
|
if (!receiverRegistered) return
|
|
|
|
try {
|
|
reactContext.unregisterReceiver(scanReceiver)
|
|
} catch (_: Exception) {}
|
|
|
|
receiverRegistered = false
|
|
}
|
|
|
|
/**
|
|
* Required for React Native NativeEventEmitter
|
|
*/
|
|
@ReactMethod
|
|
fun addListener(eventName: String) {
|
|
// No-op
|
|
}
|
|
|
|
/**
|
|
* Required for React Native NativeEventEmitter
|
|
*/
|
|
@ReactMethod
|
|
fun removeListeners(count: Int) {
|
|
// No-op
|
|
}
|
|
|
|
@ReactMethod
|
|
fun triggerScan() {
|
|
val intent = Intent().apply {
|
|
action = "com.symbol.datawedge.api.ACTION"
|
|
putExtra("com.symbol.datawedge.api.SOFT_SCAN_TRIGGER", "TOGGLE_SCANNING")
|
|
}
|
|
|
|
reactContext.sendBroadcast(intent)
|
|
}
|
|
|
|
private fun sendCommand(command: String, value: Any) {
|
|
val intent = Intent().apply {
|
|
action = "com.symbol.datawedge.api.ACTION"
|
|
|
|
when (value) {
|
|
is String -> putExtra(command, value)
|
|
is Bundle -> putExtra(command, value)
|
|
}
|
|
}
|
|
|
|
reactContext.sendBroadcast(intent)
|
|
}
|
|
|
|
private fun sendEvent(eventName: String, payload: WritableMap) {
|
|
reactContext
|
|
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
.emit(eventName, payload)
|
|
}
|
|
|
|
//
|
|
@ReactMethod
|
|
fun ensureProfile() {
|
|
val profileName = "LST_MOBILE"
|
|
|
|
// Create profile (safe to call even if it exists)
|
|
sendCommand(
|
|
"com.symbol.datawedge.api.CREATE_PROFILE",
|
|
profileName
|
|
)
|
|
|
|
Thread.sleep(500)
|
|
// Configure profile
|
|
val profileConfig = Bundle().apply {
|
|
putString("PROFILE_NAME", profileName)
|
|
putString("PROFILE_ENABLED", "true")
|
|
putString("CONFIG_MODE", "CREATE_IF_NOT_EXIST")
|
|
|
|
val barcodeConfig = Bundle().apply {
|
|
putString("PLUGIN_NAME", "BARCODE")
|
|
putString("RESET_CONFIG", "true")
|
|
|
|
val props = Bundle().apply {
|
|
putString("scanner_input_enabled", "true")
|
|
}
|
|
|
|
putBundle("PARAM_LIST", props)
|
|
}
|
|
|
|
val intentConfig = Bundle().apply {
|
|
putString("PLUGIN_NAME", "INTENT")
|
|
putString("RESET_CONFIG", "true")
|
|
|
|
val props = Bundle().apply {
|
|
putString("intent_output_enabled", "true")
|
|
putString("intent_action", scanAction)
|
|
putString("intent_delivery", "2") // broadcast
|
|
putString("intent_use_content_provider", "false") // optional but helps
|
|
}
|
|
|
|
putBundle("PARAM_LIST", props)
|
|
}
|
|
|
|
val keystrokeConfig = Bundle().apply {
|
|
putString("PLUGIN_NAME", "KEYSTROKE")
|
|
putString("RESET_CONFIG", "true")
|
|
|
|
val props = Bundle().apply {
|
|
putString("keystroke_output_enabled", "false")
|
|
}
|
|
|
|
putBundle("PARAM_LIST", props)
|
|
}
|
|
|
|
putParcelableArrayList(
|
|
"PLUGIN_CONFIG",
|
|
arrayListOf(barcodeConfig, intentConfig, keystrokeConfig)
|
|
)
|
|
}
|
|
|
|
sendCommand("com.symbol.datawedge.api.SET_CONFIG", profileConfig)
|
|
|
|
// Associate with your app
|
|
val appConfig = Bundle().apply {
|
|
putString("PACKAGE_NAME", reactContext.packageName)
|
|
putStringArray("ACTIVITY_LIST", arrayOf("*"))
|
|
}
|
|
|
|
val associateConfig = Bundle().apply {
|
|
putString("PROFILE_NAME", profileName)
|
|
putString("CONFIG_MODE", "UPDATE")
|
|
putParcelableArray("APP_LIST", arrayOf(appConfig))
|
|
}
|
|
|
|
sendCommand("com.symbol.datawedge.api.SET_CONFIG", associateConfig)
|
|
}
|
|
}
|
|
`;
|
|
|
|
const packageCode = `package ${packageName}.scanner
|
|
|
|
import com.facebook.react.ReactPackage
|
|
import com.facebook.react.bridge.NativeModule
|
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
import com.facebook.react.uimanager.ViewManager
|
|
|
|
class ZebraScannerPackage : ReactPackage {
|
|
|
|
override fun createNativeModules(
|
|
reactContext: ReactApplicationContext
|
|
): List<NativeModule> {
|
|
return listOf(ZebraScannerModule(reactContext))
|
|
}
|
|
|
|
override fun createViewManagers(
|
|
reactContext: ReactApplicationContext
|
|
): List<ViewManager<*, *>> {
|
|
return emptyList()
|
|
}
|
|
}
|
|
`;
|
|
|
|
function patchMainApplication(mainApplicationPath) {
|
|
let contents = fs.readFileSync(mainApplicationPath, "utf8");
|
|
|
|
const importLine = `import ${packageName}.scanner.ZebraScannerPackage`;
|
|
|
|
if (!contents.includes(importLine)) {
|
|
contents = contents.replace(
|
|
/import com\.facebook\.react\.PackageList/,
|
|
`import com.facebook.react.PackageList\n${importLine}`,
|
|
);
|
|
}
|
|
|
|
if (!contents.includes("add(ZebraScannerPackage())")) {
|
|
contents = contents.replace(
|
|
/PackageList\(this\)\.packages\.apply\s*\{/,
|
|
`PackageList(this).packages.apply {\n add(ZebraScannerPackage())`,
|
|
);
|
|
}
|
|
|
|
fs.writeFileSync(mainApplicationPath, contents);
|
|
}
|
|
|
|
module.exports = function withZebraScanner(config) {
|
|
return withDangerousMod(config, [
|
|
"android",
|
|
async (config) => {
|
|
const androidRoot = config.modRequest.platformProjectRoot;
|
|
|
|
const scannerDir = path.join(
|
|
androidRoot,
|
|
"app/src/main/java",
|
|
packagePath,
|
|
"scanner",
|
|
);
|
|
|
|
fs.mkdirSync(scannerDir, { recursive: true });
|
|
|
|
fs.writeFileSync(
|
|
path.join(scannerDir, "ZebraScannerModule.kt"),
|
|
moduleCode,
|
|
);
|
|
|
|
fs.writeFileSync(
|
|
path.join(scannerDir, "ZebraScannerPackage.kt"),
|
|
packageCode,
|
|
);
|
|
|
|
const mainApplicationPath = path.join(
|
|
androidRoot,
|
|
"app/src/main/java",
|
|
packagePath,
|
|
"MainApplication.kt",
|
|
);
|
|
|
|
patchMainApplication(mainApplicationPath);
|
|
|
|
return config;
|
|
},
|
|
]);
|
|
};
|