Feat(Tis): DeviceInfo and Build applicationId

Send Device name and AndroidId in DeviceInfo,
Handle multiple release version with different version number and application Id for each psp
This commit is contained in:
Amir Mousavi
2026-05-09 20:30:14 +03:30
parent d73df5524e
commit fe17187df2
16 changed files with 110 additions and 73 deletions
@@ -0,0 +1,24 @@
package com.example.core
import android.annotation.SuppressLint
import android.content.Context
import android.os.Build
import android.provider.Settings
fun getDeviceName(): String {
val manufacturer = Build.MANUFACTURER
val model = Build.MODEL
return if (model.startsWith(manufacturer, ignoreCase = true)) {
model
} else {
"$manufacturer $model"
}
}
@SuppressLint("HardwareIds")
fun getAndroidId(context: Context): String {
return Settings
.Secure
.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
}
@@ -1,9 +0,0 @@
package com.example.core.data
import com.example.core.domain.AppConfig
class AppConfigImpl : AppConfig{
override fun androidId(id: String): String {
return "window.WebV.onUUID($id);"
}
}
@@ -1,8 +1,6 @@
package com.example.core.di package com.example.core.di
import com.example.core.data.AppConfigImpl
import com.example.core.data.PaymentResultImpl import com.example.core.data.PaymentResultImpl
import com.example.core.domain.AppConfig
import com.example.core.domain.PaymentResult import com.example.core.domain.PaymentResult
import com.google.gson.Gson import com.google.gson.Gson
import dagger.Module import dagger.Module
@@ -25,9 +23,4 @@ class CoreModule {
): PaymentResult = PaymentResultImpl( ): PaymentResult = PaymentResultImpl(
gson = gson gson = gson
) )
@Provides
fun provideAppConfig(
gson: Gson
): AppConfig = AppConfigImpl()
} }
@@ -1,7 +0,0 @@
package com.example.core.domain
import com.example.core.model.PaymentResultEntity
interface AppConfig {
fun androidId(id : String) : String
}
@@ -0,0 +1,6 @@
package com.example.core.model
data class DeviceInfo(
val androidId: String,
val deviceName: String
)
@@ -3,8 +3,6 @@ package com.example.design_system
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.view.ViewGroup import android.view.ViewGroup
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebSettings import android.webkit.WebSettings
import android.webkit.WebView import android.webkit.WebView
import android.webkit.WebViewClient import android.webkit.WebViewClient
@@ -36,7 +34,7 @@ fun PspWebView(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onWebView: (WebView) -> Unit, onWebView: (WebView) -> Unit,
onPayClick: (amount: Long, id: String?) -> Unit, onPayClick: (amount: Long, id: String?) -> Unit,
onUUID: () -> Unit, onDeviceInfo: () -> String,
onPrintClick: (printEntities: List<PrintEntity>) -> Unit, onPrintClick: (printEntities: List<PrintEntity>) -> Unit,
) { ) {
@@ -49,13 +47,13 @@ fun PspWebView(
// Use rememberUpdatedState to ensure the bridge always calls the latest callbacks // Use rememberUpdatedState to ensure the bridge always calls the latest callbacks
val currentOnPayClick by rememberUpdatedState(onPayClick) val currentOnPayClick by rememberUpdatedState(onPayClick)
val currentOnPrintClick by rememberUpdatedState(onPrintClick) val currentOnPrintClick by rememberUpdatedState(onPrintClick)
val currentOnUUID by rememberUpdatedState(onUUID) val currentOnDeviceInfo by rememberUpdatedState(onDeviceInfo)
val bridge = remember { val bridge = remember {
PspJavaScriptInterface( PspJavaScriptInterface(
onPayClick = { amount, id -> currentOnPayClick(amount, id) }, onPayClick = { amount, id -> currentOnPayClick(amount, id) },
onPrintClick = { entities -> currentOnPrintClick(entities) }, onPrintClick = { entities -> currentOnPrintClick(entities) },
onUUID = { currentOnUUID() } onDeviceInfo = { currentOnDeviceInfo() }
) )
} }
@@ -11,7 +11,7 @@ import com.google.gson.reflect.TypeToken
class PspJavaScriptInterface( class PspJavaScriptInterface(
private val onPayClick: (Long, String?) -> Unit, private val onPayClick: (Long, String?) -> Unit,
private val onPrintClick: (List<PrintEntity>) -> Unit, private val onPrintClick: (List<PrintEntity>) -> Unit,
private val onUUID: () -> Unit, private val onDeviceInfo: () -> String,
) { ) {
@JavascriptInterface @JavascriptInterface
@@ -40,12 +40,13 @@ class PspJavaScriptInterface(
@JavascriptInterface @JavascriptInterface
@Keep @Keep
fun uuid() { fun deviceInfo(): String {
Log.d("PspBridge", "uuid called") Log.d("PspBridge", "uuid called")
try { return try {
onUUID() onDeviceInfo()
} catch (e: Exception) { } catch (e: Exception) {
Log.e("PspBridge", "Error in uuid callback", e) Log.e("PspBridge", "Error in uuid callback", e)
""
} }
} }
} }
@@ -1,15 +1,12 @@
package com.example.ps4 package com.example.ps4
import android.content.Context
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import com.example.core.domain.Printer import com.example.core.domain.Printer
import com.example.core.model.PrintEntity import com.example.core.model.PrintEntity
import javax.inject.Inject import javax.inject.Inject
class P4Printer @Inject constructor( class P4Printer @Inject constructor() : Printer {
private val context: Context,
) : Printer {
override fun print( override fun print(
+18 -4
View File
@@ -2,10 +2,12 @@ plugins {
alias(libs.plugins.android.application) alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.compose) alias(libs.plugins.kotlin.compose)
alias(libs.plugins.ksp) alias(libs.plugins.ksp)
alias(libs.plugins.hilt)} alias(libs.plugins.hilt)
}
android { android {
namespace = "com.example.stage_app" namespace = "com.example.stage_app"
compileSdk { compileSdk {
version = release(36) { version = release(36) {
minorApiLevel = 1 minorApiLevel = 1
@@ -16,22 +18,33 @@ android {
applicationId = "com.example.stage_app" applicationId = "com.example.stage_app"
minSdk = 24 minSdk = 24
targetSdk = 36 targetSdk = 36
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
flavorDimensions.add("module") flavorDimensions.add("module")
productFlavors { productFlavors {
create("p3") { create("p3") {
versionCode = 1
versionName = "1.0"
dimension = "module" dimension = "module"
applicationId = "com.example.stage_app_p3"
manifestPlaceholders["appName"] = "TisP3"
} }
create("ps4") { create("ps4") {
versionCode = 1
versionName = "2.0"
dimension = "module" dimension = "module"
applicationId = "com.example.stage_app_p4"
manifestPlaceholders["appName"] = "TisP4"
} }
create("standard") { create("standard") {
versionCode = 1
versionName = "1.0"
dimension = "module" dimension = "module"
applicationId = "com.example.stage_app"
manifestPlaceholders["appName"] = "Tis"
} }
} }
@@ -74,6 +87,7 @@ dependencies {
implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.retrofit.converter.gson)
implementation("androidx.hilt:hilt-navigation-compose:1.2.0") implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
testImplementation(libs.junit) testImplementation(libs.junit)
androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(platform(libs.androidx.compose.bom))
+1 -1
View File
@@ -20,7 +20,7 @@
android:name=".PspApplication" android:name=".PspApplication"
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="${appName}"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.PSP" android:theme="@style/Theme.PSP"
@@ -1,6 +1,5 @@
package com.example.stage_app.screen package com.example.stage_app.screen
import android.provider.Settings
import android.webkit.WebView import android.webkit.WebView
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
@@ -13,6 +12,8 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.example.core.getAndroidId
import com.example.core.getDeviceName
import com.example.design_system.PspWebView import com.example.design_system.PspWebView
import com.example.stage_app.viewmodel.StageViewModel import com.example.stage_app.viewmodel.StageViewModel
@@ -60,13 +61,10 @@ fun StageWebViewScreen(
viewModel.print(printEntities) viewModel.print(printEntities)
}, },
onUUID = { onDeviceInfo = {
val androidId = Settings viewModel.deviceInfoJson(
.Secure androidId = getAndroidId(context),
.getString(context.contentResolver, Settings.Secure.ANDROID_ID) getDeviceName()
viewModel.sendAndroidId(
androidId
) )
} }
) )
@@ -3,12 +3,13 @@ package com.example.stage_app.viewmodel
import android.content.Intent import android.content.Intent
import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResult
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.example.core.domain.AppConfig
import com.example.core.domain.PaymentResult import com.example.core.domain.PaymentResult
import com.example.core.domain.Printer import com.example.core.domain.Printer
import com.example.core.domain.PspService import com.example.core.domain.PspService
import com.example.core.model.DeviceInfo
import com.example.core.model.PaymentResultEntity import com.example.core.model.PaymentResultEntity
import com.example.core.model.PrintEntity import com.example.core.model.PrintEntity
import com.google.gson.Gson
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject import javax.inject.Inject
@@ -17,7 +18,7 @@ class StageViewModel @Inject constructor(
private val pspService: PspService, private val pspService: PspService,
private val paymentResult: PaymentResult, private val paymentResult: PaymentResult,
private val printer: Printer, private val printer: Printer,
private val appConfig: AppConfig private val gson: Gson
) : ViewModel() { ) : ViewModel() {
@@ -66,7 +67,12 @@ class StageViewModel @Inject constructor(
) )
} }
fun sendAndroidId(id: String) { fun deviceInfoJson(androidId: String, deviceName: String): String {
appConfig.androidId(id) return gson.toJson(
DeviceInfo(
androidId = androidId,
deviceName = deviceName
)
)
} }
} }
@@ -1,8 +1,9 @@
package com.example.tis_sep.di package com.example.tis_sep.di
import com.example.core.PspService import com.example.core.domain.Printer
import com.example.ps4.Ps4Service import com.example.core.domain.PspService
import com.example.ps4.P4Printer import com.example.ps4.P4Printer
import com.example.ps4.Ps4Service
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
+13 -5
View File
@@ -17,23 +17,30 @@ android {
applicationId = "com.example.tis_app" applicationId = "com.example.tis_app"
minSdk = 24 minSdk = 24
targetSdk = 36 targetSdk = 36
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
flavorDimensions.add("module") flavorDimensions.add("module")
productFlavors { productFlavors {
create("p3") { create("p3") {
versionCode = 1
versionName = "1.0"
dimension = "module" dimension = "module"
applicationId = "com.example.tis_app_p3"
manifestPlaceholders["appName"] = "تیس"
} }
create("ps4") { create("ps4") {
versionCode = 1
versionName = "1.0"
dimension = "module" dimension = "module"
} applicationId = "com.example.tis_app_p4"
manifestPlaceholders["appName"] = "تیس" }
create("standard") { create("standard") {
versionCode = 1
versionName = "1.0"
dimension = "module" dimension = "module"
} applicationId = "com.example.tis_app"
manifestPlaceholders["appName"] = "تیس" }
} }
buildTypes { buildTypes {
@@ -72,6 +79,7 @@ dependencies {
implementation(libs.androidx.compose.ui.graphics) implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
implementation(libs.retrofit.converter.gson)
implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.lifecycle.runtime.ktx)
implementation("androidx.hilt:hilt-navigation-compose:1.2.0") implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
testImplementation(libs.junit) testImplementation(libs.junit)
@@ -1,6 +1,5 @@
package com.example.tis_app.screen package com.example.tis_app.screen
import android.provider.Settings
import android.webkit.WebView import android.webkit.WebView
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
@@ -13,9 +12,13 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.example.core.getAndroidId
import com.example.core.getDeviceName
import com.example.design_system.PspWebView import com.example.design_system.PspWebView
import com.example.tis_app.viewmodel.WebViewModel import com.example.tis_app.viewmodel.WebViewModel
private const val tisIp = "194.59.214.243:8090" private const val tisIp = "194.59.214.243:8090"
@Composable @Composable
fun TisWebViewScreen( fun TisWebViewScreen(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@@ -58,13 +61,10 @@ fun TisWebViewScreen(
viewModel.print(printEntities) viewModel.print(printEntities)
}, },
onUUID = { onDeviceInfo = {
val androidId = Settings viewModel.deviceInfoJson(
.Secure androidId = getAndroidId(context),
.getString(context.contentResolver, Settings.Secure.ANDROID_ID) getDeviceName()
viewModel.sendAndroidId(
androidId
) )
} }
) )
@@ -3,13 +3,14 @@ package com.example.tis_app.viewmodel
import android.content.Intent import android.content.Intent
import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResult
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.example.core.domain.AppConfig
import com.example.core.domain.PaymentResult import com.example.core.domain.PaymentResult
import com.example.core.domain.Printer import com.example.core.domain.Printer
import com.example.core.domain.PspService import com.example.core.domain.PspService
import com.example.core.model.DeviceInfo
import com.example.core.model.PaymentResultEntity import com.example.core.model.PaymentResultEntity
import com.example.core.model.PrintEntity import com.example.core.model.PrintEntity
import com.example.tis_app.R import com.example.tis_app.R
import com.google.gson.Gson
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject import javax.inject.Inject
@@ -18,7 +19,7 @@ class WebViewModel @Inject constructor(
private val pspService: PspService, private val pspService: PspService,
private val paymentResult: PaymentResult, private val paymentResult: PaymentResult,
private val printer: Printer, private val printer: Printer,
private val appConfig: AppConfig private val gson: Gson
) : ViewModel() { ) : ViewModel() {
@@ -37,14 +38,20 @@ class WebViewModel @Inject constructor(
activityResult = activityResult activityResult = activityResult
) )
} }
fun print(printEntities : List<PrintEntity>) {
fun print(printEntities: List<PrintEntity>) {
printer.print( printer.print(
printEntities = printEntities, printEntities = printEntities,
icon = R.drawable.tis_icon icon = R.drawable.tis_icon
) )
} }
fun sendAndroidId(id : String) { fun deviceInfoJson(androidId: String, deviceName: String): String {
appConfig.androidId(id) return gson.toJson(
DeviceInfo(
androidId = androidId,
deviceName = deviceName
)
)
} }
} }