Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 27 additions & 15 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
buildscript {

// Buildscript is evaluated before everything else so we can't use getExtOrDefault
def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["SunmiExternalPrinterReactNative_kotlinVersion"]

Expand All @@ -9,7 +8,7 @@ buildscript {
}

dependencies {
classpath "com.android.tools.build:gradle:7.2.1"
classpath "com.android.tools.build:gradle:8.9.1"
// noinspection DifferentKotlinGradleVersion
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
Expand All @@ -22,9 +21,6 @@ def isNewArchitectureEnabled() {
apply plugin: "com.android.library"
apply plugin: "kotlin-android"


def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }

if (isNewArchitectureEnabled()) {
apply plugin: "com.facebook.react"
}
Expand All @@ -38,13 +34,19 @@ def getExtOrIntegerDefault(name) {
}

android {
namespace "com.sunmiexternalprinter"
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")

defaultConfig {
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
}

buildFeatures {
buildConfig true
}

buildTypes {
release {
minifyEnabled false
Expand All @@ -56,10 +58,23 @@ android {
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}

kotlinOptions {
jvmTarget = "17"
}

sourceSets {
main {
if (isNewArchitectureEnabled()) {
java.srcDirs += ["build/generated/source/codegen/java"]
} else {
java.srcDirs += ["src/oldarch/java"]
}
}
}
}

repositories {
Expand All @@ -78,15 +93,12 @@ dependencies {
// For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
implementation 'com.facebook.react:react-android:+'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'com.github.DantSu:ESCPOS-ThermalPrinter-Android:3.2.0'
implementation 'androidx.core:core:1.7.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.github.DantSu:ESCPOS-ThermalPrinter-Android:3.4.0'
implementation 'androidx.core:core:1.17.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'com.github.anastaciocintra:escpos-coffee:4.1.0'
implementation 'com.izettle:html2bitmap:1.9'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'



implementation 'com.izettle:html2bitmap:1.10'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
}

if (isNewArchitectureEnabled()) {
Expand Down
8 changes: 4 additions & 4 deletions android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
#Sat May 27 13:02:33 BST 2023
SunmiExternalPrinterReactNative_kotlinVersion=1.7.0
SunmiExternalPrinterReactNative_compileSdkVersion=31
SunmiExternalPrinterReactNative_targetSdkVersion=31
SunmiExternalPrinterReactNative_minSdkVersion=21
SunmiExternalPrinterReactNative_kotlinVersion=2.0.21
SunmiExternalPrinterReactNative_compileSdkVersion=35
SunmiExternalPrinterReactNative_targetSdkVersion=35
SunmiExternalPrinterReactNative_minSdkVersion=28
SunmiExternalPrinterReactNative_ndkversion=21.4.7075529
android.useAndroidX=true
android.enableJetifier=true
Expand Down
3 changes: 2 additions & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#Mon Dec 01 21:54:28 WIB 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ import kotlinx.coroutines.sync.Semaphore
* @since 1.0.0
*/
class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext) {
NativeSunmiExternalPrinterSpec(reactContext) {
/** Current promise for async operations - ensures single operation at a time */
private var promise: Promise? = null

Expand Down Expand Up @@ -213,18 +213,26 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
override fun onServiceLost(p0: NsdServiceInfo?) {}
}

// getName() is provided by NativeSunmiExternalPrinterSpec for New Architecture
// For Old Architecture, NativeSunmiExternalPrinterSpec extends ReactContextBaseJavaModule
// which requires getName() to be overridden
override fun getName(): String {
return NAME
}

// Property to access ReactApplicationContext in Kotlin style
// Works for both Old and New Architecture
protected val reactAppContext: ReactApplicationContext
get() = reactApplicationContext

/**
* Acquires the printing semaphore to ensure exclusive access to printing operations. This
* prevents multiple concurrent print jobs that could interfere with each other.
*
* @param promise Promise that resolves when semaphore is acquired
*/
@ReactMethod
fun lockPrintingSemaphore(promise: Promise) {
override fun lockPrintingSemaphore(promise: Promise) {
Thread {
runBlocking {
printingSemaphore.acquire()
Expand All @@ -241,7 +249,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
* @param promise Promise that resolves when semaphore is released
*/
@ReactMethod
fun unlockPrintingSemaphore(promise: Promise) {
override fun unlockPrintingSemaphore(promise: Promise) {
Thread {
runBlocking {
printingSemaphore.release()
Expand All @@ -260,7 +268,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
* @param promise Promise that resolves with Base64 string or rejects with error
*/
@ReactMethod
fun convertHTMLtoBase64(htmlString: String, width: Int, promise: Promise) {
override fun convertHTMLtoBase64(htmlString: String, width: Double, promise: Promise) {
this.promise = promise
Thread {
try {
Expand All @@ -276,7 +284,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
.setContext(reactApplicationContext.applicationContext)
.setConfigurator(html2BitmapConfigurator)
.setContent(WebViewContent.html(htmlString))
.setBitmapWidth(width)
.setBitmapWidth(width.toInt())
.build()
.bitmap
// val resizedBitmap = Bitmap.createScaledBitmap(
Expand All @@ -288,7 +296,8 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
val byteArrayOutputStream = ByteArrayOutputStream()
bitmap?.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)
val byteArray = byteArrayOutputStream.toByteArray()
val base64String = Base64.encodeToString(byteArray, Base64.DEFAULT)
// Use NO_WRAP for single-line output (modern standard, better compatibility)
val base64String = Base64.encodeToString(byteArray, Base64.NO_WRAP)
promise.resolve(base64String)
} catch (e: java.lang.Exception) {
e.printStackTrace()
Expand All @@ -305,7 +314,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
*/
@Suppress("DEPRECATION")
@ReactMethod
fun getListofServiceNames(promise: Promise) {
override fun getListofServiceNames(promise: Promise) {
val activityManager: ActivityManager =
reactApplicationContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val services: WritableArray = Arguments.createArray()
Expand All @@ -326,7 +335,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
* @param promise Promise that resolves on success or rejects on error
*/
@ReactMethod
fun printImageWithTCPRasterBitImageWrapper(
override fun printImageWithTCPRasterBitImageWrapper(
base64Image: String,
ipAddress: String,
port: String,
Expand All @@ -337,7 +346,8 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex

Thread {
try {
val encodedBase64 = Base64.decode(base64Image, Base64.DEFAULT)
// Use NO_WRAP to handle base64 strings with or without line breaks
val encodedBase64 = Base64.decode(base64Image, Base64.NO_WRAP)
val bitmap = BitmapFactory.decodeByteArray(encodedBase64, 0, encodedBase64.size)
val scaledBitmap =
Bitmap.createScaledBitmap(bitmap, bitmap.width, bitmap.height, true)
Expand Down Expand Up @@ -384,7 +394,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
* @param promise Promise that resolves on success or rejects on error
*/
@ReactMethod
fun printImageWithTCPBitImageWrapper(
override fun printImageWithTCPBitImageWrapper(
base64Image: String,
ipAddress: String,
port: String,
Expand All @@ -395,7 +405,8 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex

Thread {
try {
val encodedBase64 = Base64.decode(base64Image, Base64.DEFAULT)
// Use NO_WRAP to handle base64 strings with or without line breaks
val encodedBase64 = Base64.decode(base64Image, Base64.NO_WRAP)
val bitmap = BitmapFactory.decodeByteArray(encodedBase64, 0, encodedBase64.size)
val scaledBitmap =
Bitmap.createScaledBitmap(bitmap, bitmap.width, bitmap.height, true)
Expand Down Expand Up @@ -441,7 +452,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
* @param promise Promise that resolves on success or rejects on error
*/
@ReactMethod
fun printImageWithGraphicsImageWrapper(
override fun printImageWithGraphicsImageWrapper(
base64Image: String,
ipAddress: String,
port: String,
Expand All @@ -452,7 +463,8 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex

Thread {
try {
val encodedBase64 = Base64.decode(base64Image, Base64.DEFAULT)
// Use NO_WRAP to handle base64 strings with or without line breaks
val encodedBase64 = Base64.decode(base64Image, Base64.NO_WRAP)
val bitmap = BitmapFactory.decodeByteArray(encodedBase64, 0, encodedBase64.size)
val scaledBitmap =
Bitmap.createScaledBitmap(bitmap, bitmap.width, bitmap.height, true)
Expand Down Expand Up @@ -494,7 +506,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
* @param promise Promise that resolves when discovery starts or rejects on error
*/
@ReactMethod
fun startDiscovery(promise: Promise) {
override fun startDiscovery(promise: Promise) {
try {
nsdManager =
reactApplicationContext.applicationContext.getSystemService(Context.NSD_SERVICE) as
Expand All @@ -519,7 +531,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
* @param promise Promise that resolves when drawer command is sent
*/
@ReactMethod
fun openDrawer(ipAddress: String, port: String, promise: Promise) {
override fun openDrawer(ipAddress: String, port: String, promise: Promise) {
this.promise = promise
Thread {
try {
Expand All @@ -543,7 +555,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
* @param promise Promise that resolves when discovery is stopped
*/
@ReactMethod
fun stopDiscovery(promise: Promise) {
override fun stopDiscovery(promise: Promise) {
try {
if (nsdManager !== null) {
nsdManager?.stopServiceDiscovery(discoveryListener)
Expand Down Expand Up @@ -700,7 +712,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
*/
@SuppressLint("MissingPermission")
@ReactMethod
private fun scanBLDevice(promise: Promise) {
override fun scanBLDevice(promise: Promise) {
bleScanResults.clear()
bleScanResultsDataClass.clear()
Log.d("Size:", "${bleScanResults.size}")
Expand Down Expand Up @@ -739,7 +751,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
*/
@SuppressLint("MissingPermission")
@ReactMethod
private fun printImageByBluetooth(
override fun printImageByBluetooth(
address: String,
base64Image: String,
cut: String,
Expand All @@ -756,7 +768,8 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
e.printStackTrace()
}
escpos = EscPos(stream)
val encodedBase64 = Base64.decode(base64Image, Base64.DEFAULT)
// Use NO_WRAP to handle base64 strings with or without line breaks
val encodedBase64 = Base64.decode(base64Image, Base64.NO_WRAP)
val bitmap = BitmapFactory.decodeByteArray(encodedBase64, 0, encodedBase64.size)
val scaledBitmap =
Bitmap.createScaledBitmap(bitmap, bitmap.width - 40, bitmap.height, true)
Expand Down Expand Up @@ -790,7 +803,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
*/
@SuppressLint("MissingPermission")
@ReactMethod
private fun printCutByBluetooth(address: String, addresspromise: Promise) {
override fun printCutByBluetooth(address: String, addresspromise: Promise) {
this.promise = addresspromise
println("Here Inside the function in android ")
Thread {
Expand Down Expand Up @@ -829,7 +842,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
*/
@SuppressLint("MissingPermission")
@ReactMethod
private fun closePrinterSocket(promise: Promise) {
override fun closePrinterSocket(promise: Promise) {
try {
stream!!.closeSocket()
promise.resolve("Socket close")
Expand All @@ -846,7 +859,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
*/
@SuppressLint("MissingPermission")
@ReactMethod
private fun closeTCPPrinterSocket(promise: Promise) {
override fun closeTCPPrinterSocket(promise: Promise) {
if (tcpStream != null) {
tcpStream!!.closeSocket(promise)
} else {
Expand All @@ -862,7 +875,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
*/
@SuppressLint("MissingPermission")
@ReactMethod
private fun getPairedDevices(promise: Promise) {
override fun getPairedDevices(promise: Promise) {
try {
this.promise = promise
println("Here Inside the function in android ")
Expand All @@ -882,7 +895,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
* @param promise Promise that resolves when drawer command is sent
*/
@ReactMethod
fun openDrawerBluetooth(macAddress: String, promise: Promise) {
override fun openDrawerBluetooth(macAddress: String, promise: Promise) {
this.promise = promise
Thread {
try {
Expand Down Expand Up @@ -917,7 +930,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
*/
@SuppressLint("unused", "UnspecifiedRegisterReceiverFlag", "InlinedApi")
@ReactMethod
fun printUSBDevice(
override fun printUSBDevice(
productID: String,
vendorId: String,
base64String: String,
Expand Down Expand Up @@ -987,7 +1000,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
*/
@SuppressLint("unused", "UnspecifiedRegisterReceiverFlag", "InlinedApi")
@ReactMethod
fun openDrawerUSB(productID: String, vendorId: String, promise: Promise) {
override fun openDrawerUSB(productID: String, vendorId: String, promise: Promise) {
Thread {
try {
val manager =
Expand Down Expand Up @@ -1048,7 +1061,7 @@ class SunmiExternalPrinterReactNativeModule(reactContext: ReactApplicationContex
@RequiresApi(Build.VERSION_CODES.M)
@SuppressLint("unused")
@ReactMethod
fun searchUSBDevices(promise: Promise) {
override fun searchUSBDevices(promise: Promise) {
try {
val manager = reactApplicationContext.getSystemService(Context.USB_SERVICE) as UsbManager
val deviceList = manager.getDeviceList()
Expand Down
Loading