diff --git a/android-sdk/build.gradle b/android-sdk/build.gradle index f679998..7e16d4a 100644 --- a/android-sdk/build.gradle +++ b/android-sdk/build.gradle @@ -96,39 +96,36 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation libs.kotlinStdlib - implementation libs.appCompat - - implementation libs.coroutinesCore - implementation libs.coroutinesAndroid - - implementation libs.workmanager - - implementation libs.okHttp - - implementation libs.room - implementation libs.roomKtx - testImplementation 'junit:junit:4.13.2' - kapt libs.roomCompiler - - testImplementation libs.junit - testImplementation libs.androidTestCore - testImplementation libs.mockk - testImplementation libs.coroutinesTest - testImplementation libs.kotlinTest - - androidTestImplementation libs.androidTestJunit - androidTestImplementation libs.androidTestCore - androidTestImplementation libs.runner - androidTestImplementation libs.androidMockk - androidTestImplementation libs.androidArchCoreTest - - androidTestImplementation libs.androidRoomTest - androidTestImplementation libs.androidWorkmanagerTest - androidTestImplementation libs.truth - testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.3' - //testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2' - //api group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.25' + implementation ("androidx.appcompat:appcompat:1.7.0") + implementation ("org.jetbrains.kotlin:kotlin-stdlib:1.9.24") + + implementation ("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1") + implementation ("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1") + + implementation ("androidx.work:work-runtime-ktx:2.9.1") + + implementation ("com.squareup.okhttp3:okhttp:4.12.0") + + implementation ("androidx.room:room-runtime:2.6.1") + implementation ("androidx.room:room-ktx:2.6.1") + kapt ("androidx.room:room-compiler:2.6.1") + + testImplementation ("junit:junit:4.13.2") + testImplementation ("androidx.test:core:1.6.1") + testImplementation ("io.mockk:mockk:1.13.12") + testImplementation ("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1") + testImplementation ("io.kotlintest:kotlintest-runner-junit5:3.4.2") + testImplementation ("org.junit.jupiter:junit-jupiter-engine:5.10.3") + + androidTestImplementation ("androidx.test.ext:junit:1.2.1") + androidTestImplementation ("androidx.test:core:1.6.1") + androidTestImplementation ("androidx.test:runner:1.6.2") + androidTestImplementation ("io.mockk:mockk-android:1.13.12") + //androidTestImplementation ("androidx.arch.core:core-testing:2.2.0") + + androidTestImplementation ("androidx.room:room-testing:2.6.1") + androidTestImplementation ("androidx.work:work-testing:2.9.1") + androidTestImplementation ("com.google.truth:truth:1.4.4") } /** diff --git a/android-sdk/src/main/java/webtrekk/android/sdk/core/SchedulerImpl.kt b/android-sdk/src/main/java/webtrekk/android/sdk/core/SchedulerImpl.kt index 8e432bb..2d07baa 100644 --- a/android-sdk/src/main/java/webtrekk/android/sdk/core/SchedulerImpl.kt +++ b/android-sdk/src/main/java/webtrekk/android/sdk/core/SchedulerImpl.kt @@ -33,6 +33,7 @@ import androidx.work.ExistingWorkPolicy import androidx.work.OneTimeWorkRequest import androidx.work.OutOfQuotaPolicy import androidx.work.PeriodicWorkRequest +import androidx.work.PeriodicWorkRequestBuilder import androidx.work.WorkInfo import androidx.work.WorkManager import kotlinx.coroutines.sync.Mutex @@ -82,16 +83,34 @@ internal class SchedulerImpl( } } + // To be changed to clean up after executing the requests + override fun scheduleCleanUp() { + val data = Data.Builder().apply { + putStringArray("trackIds", config.trackIds.toTypedArray()) + putString("trackDomain", config.trackDomain) + }.build() + + val cleanWorkBuilder = PeriodicWorkRequestBuilder(60, TimeUnit.MINUTES) + .addTag(CleanUpWorker.TAG) + .setInitialDelay(5, TimeUnit.MINUTES) + .setInputData(data) + + workManager.enqueueUniquePeriodicWork( + CLEAN_UP_WORKER, + ExistingPeriodicWorkPolicy.UPDATE, + cleanWorkBuilder.build() + ) + } + override fun sendRequestsThenCleanUp() { webtrekkLogger.debug("SEND WORKER - sendRequestsThenCleanUp") synchronized(mutex) { // check if SendRequestsWorker already running as periodic work request -// val future = workManager.getWorkInfosByTag(SendRequestsWorker.TAG) -// val workers = future.get() -// if (workers.none { it.state in listOf(WorkInfo.State.RUNNING) }) { -// scheduleSendAndCleanWorkers() -// } - scheduleSendAndCleanWorkers() + val future = workManager.getWorkInfosForUniqueWork(ONE_TIME_REQUEST) + val workers = future.get() + if (workers.none { it.state in listOf(WorkInfo.State.RUNNING) }) { + scheduleSendAndCleanWorkers() + } } } @@ -102,8 +121,8 @@ internal class SchedulerImpl( }.build() val sendWorkBuilder = OneTimeWorkRequest.Builder(SendRequestsWorker::class.java) - .addTag(SendRequestsWorker.TAG) .setInputData(data) + .addTag(SendRequestsWorker.TAG) val cleanWorkBuilder = OneTimeWorkRequest.Builder(CleanUpWorker::class.java) .setInputData(data) @@ -114,42 +133,24 @@ internal class SchedulerImpl( cleanWorkBuilder.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) } - workManager.enqueueUniqueWork( + workManager.beginUniqueWork( ONE_TIME_REQUEST, - ExistingWorkPolicy.APPEND_OR_REPLACE, - listOf(sendWorkBuilder.build(), cleanWorkBuilder.build()) - ) - } - - // To be changed to clean up after executing the requests - override fun scheduleCleanUp() { - val data = Data.Builder().apply { - putStringArray("trackIds", config.trackIds.toTypedArray()) - putString("trackDomain", config.trackDomain) - }.build() - - val cleanWorkBuilder = OneTimeWorkRequest.Builder(CleanUpWorker::class.java) - .addTag(CleanUpWorker.TAG) - .setInputData(data) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - cleanWorkBuilder.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) - } - - workManager.enqueueUniqueWork( - "CleanUpWorker", - ExistingWorkPolicy.APPEND_OR_REPLACE, - cleanWorkBuilder.build() + ExistingWorkPolicy.REPLACE, + sendWorkBuilder.build() ) + .then(cleanWorkBuilder.build()) + .enqueue() } override fun cancelScheduleSendRequests() { - workManager.cancelAllWorkByTag(CleanUpWorker.TAG) - workManager.cancelAllWorkByTag(SendRequestsWorker.TAG) + workManager.cancelUniqueWork(CLEAN_UP_WORKER) + workManager.cancelUniqueWork(ONE_TIME_REQUEST) + workManager.cancelUniqueWork(SEND_REQUESTS_WORKER) } companion object { const val SEND_REQUESTS_WORKER = "send_requests_worker" const val ONE_TIME_REQUEST = "one_time_request_send_and_clean" + const val CLEAN_UP_WORKER = "CleanUpWorker" } } diff --git a/build.gradle b/build.gradle index fba5fb6..eb255c1 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ buildscript { ext.versions = [ 'webtrekkVersion' : '5.0.0', 'gradleVersion' : '3.6.4', - 'kotlinVersion' : '1.9.24',//'1.4.32', + 'kotlinVersion' : '1.9.24', 'gradleVersionsPlugin' : '0.21.0', 'mavenPluginVersion' : '2.1', 'bintrayPluginVersion' : '1.8.4', @@ -41,61 +41,6 @@ buildscript { 'minSdkVersion' : 21, 'targetSdkVersion' : 34, 'buildTools' : '34.0.0', - - 'appCompatVersion' : '1.7.0', - 'constraintLayoutVersion': '2.1.4', - - 'kotlinCoroutines' : '1.8.1', - 'coreKtxVersion' : '1.13.1', - - 'okHttpVersion' : '4.12.0', - - 'workManagerVersion' : '2.9.0', - 'roomVersion' : '2.6.1', - - 'testCoreVersion' : '1.6.1', - 'testCoreVersionJunit' : '1.2.1', - 'junitVersion' : '4.13.2', - 'runnerVersion' : '1.6.1', - 'espressoCoreVersion' : '3.5.1', - //Version 2.1.0 depends on androidx.arch.core:core-runtime:2.1.0 which must be explicitly added in android-sdk gradle - 'coreTestingVersion' : '2.2.0', - //Downgraded version from 1.9.3 to 1.9.2 while this issue is not resolved - //https://github.com/mockk/mockk/issues/281 - 'mockkVersion' : '1.13.12', - 'kotlinTestVersion' : '3.4.2', - - 'ktlintVersion' : '0.31.0', - 'dokkaVersion' : '0.9.17', - 'googleServices' : '4.3.14', - 'firebaseAppDistribution': '2.1.1' - ] - - ext.libs = [ - kotlinStdlib : "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlinVersion", - appCompat : "androidx.appcompat:appcompat:$versions.appCompatVersion", - coreKtx : "androidx.core:core-ktx:$versions.coreKtxVersion", - constraintLayout : "androidx.constraintlayout:constraintlayout:$versions.constraintLayoutVersion", - coroutinesCore : "org.jetbrains.kotlinx:kotlinx-coroutines-core:$versions.kotlinCoroutines", - coroutinesAndroid : "org.jetbrains.kotlinx:kotlinx-coroutines-android:$versions.kotlinCoroutines", - okHttp : "com.squareup.okhttp3:okhttp:$versions.okHttpVersion", - room : "androidx.room:room-runtime:$versions.roomVersion", - roomKtx : "androidx.room:room-ktx:$versions.roomVersion", - roomCompiler : "androidx.room:room-compiler:$versions.roomVersion", - workmanager : "androidx.work:work-runtime-ktx:$versions.workManagerVersion", - junit : "junit:junit:$versions.junitVersion", - runner : "androidx.test:runner:$versions.runnerVersion", - espresso : "androidx.test.espresso:espresso-core:$versions.espressoCoreVersion", - androidTestCore : "androidx.test:core:$versions.testCoreVersion", - mockk : "io.mockk:mockk:$versions.mockkVersion", - coroutinesTest : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$versions.kotlinCoroutines", - kotlinTest : "io.kotlintest:kotlintest-runner-junit5:$versions.kotlinTestVersion", - androidTestJunit : "androidx.test.ext:junit:$versions.testCoreVersionJunit", - androidMockk : "io.mockk:mockk-android:$versions.mockkVersion", - androidArchCoreTest : "androidx.arch.core:core-testing:$versions.coreTestingVersion", - androidRoomTest : "androidx.room:room-testing:$versions.roomVersion", - androidWorkmanagerTest: "androidx.work:work-testing:$versions.workManagerVersion", - truth : "com.google.truth:truth:1.4.4" ] repositories { @@ -106,12 +51,12 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:8.2.2' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlinVersion}" - classpath "com.github.ben-manes:gradle-versions-plugin:${versions.gradleVersionsPlugin}" - classpath "org.jetbrains.dokka:dokka-android-gradle-plugin:${versions.dokkaVersion}" - classpath "com.github.dcendents:android-maven-gradle-plugin:${versions.mavenPluginVersion}" - classpath "com.google.gms:google-services:${versions.googleServices}" - classpath "com.google.firebase:firebase-appdistribution-gradle:${versions.firebaseAppDistribution}" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.24" + classpath "com.github.ben-manes:gradle-versions-plugin:0.21.0" + classpath "org.jetbrains.dokka:dokka-android-gradle-plugin:0.9.17" + classpath "com.github.dcendents:android-maven-gradle-plugin:2.1" + classpath "com.google.gms:google-services:4.4.2" + classpath "com.google.firebase:firebase-appdistribution-gradle:5.0.0" classpath 'com.google.firebase:firebase-crashlytics-gradle:3.0.2' classpath 'io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.30.0' } diff --git a/sample/build.gradle b/sample/build.gradle index c4b3fd5..efe8a21 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -131,7 +131,8 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$versions.kotlinVersion" //implementation 'androidx.recyclerview:recyclerview:1.3.2' - implementation('com.google.android.material:material:1.10.0') + implementation ("androidx.activity:activity:1.9.2") + implementation('com.google.android.material:material:1.12.0') implementation "androidx.constraintlayout:constraintlayout:$versions.constraintLayoutVersion" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$versions.kotlinCoroutines" implementation "androidx.work:work-runtime-ktx:$versions.workManagerVersion" @@ -145,30 +146,19 @@ dependencies { implementation 'androidx.media3:media3-exoplayer-dash:1.4.1' implementation 'androidx.media3:media3-exoplayer-hls:1.4.1' - implementation platform('com.google.firebase:firebase-bom:33.3.0') + implementation platform('com.google.firebase:firebase-bom:33.4.0') implementation('com.google.firebase:firebase-messaging') implementation("com.google.firebase:firebase-crashlytics") implementation('com.mapp.sdk:mapp-android:6.0.24') - implementation(project(':android-sdk')) { - exclude(group: "androidx.appcompat", module: "appcompat") - } -// implementation("com.mapp.sdk:intelligence-android:5.1.10") { -// exclude(group: "androidx.appcompat", module: "appcompat") -// } + //implementation(project(':android-sdk')) + + implementation("com.mapp.sdk:intelligence-android:5.1.9") //debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1' testImplementation "junit:junit:$versions.junitVersion" androidTestImplementation "androidx.test:runner:$versions.runnerVersion" androidTestImplementation "androidx.test.espresso:espresso-core:$versions.espressoCoreVersion" -} - -//configurations.configureEach { -// resolutionStrategy.eachDependency { details -> -// if (details.requested.group == 'androidx.appcompat') { -// details.useVersion '1.7.0' -// } -// } -//} \ No newline at end of file +} \ No newline at end of file diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index d1fed22..3ad00d5 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -15,9 +15,12 @@ android:usesCleartextTraffic="true" tools:ignore="GoogleAppIndexingWarning" tools:targetApi="m"> + + android:exported="false" /> @@ -76,7 +79,7 @@ android:exported="false" /> diff --git a/sample/src/main/java/com/example/webtrekk/androidsdk/MainActivity.kt b/sample/src/main/java/com/example/webtrekk/androidsdk/MainActivity.kt index f81d755..104a8fb 100644 --- a/sample/src/main/java/com/example/webtrekk/androidsdk/MainActivity.kt +++ b/sample/src/main/java/com/example/webtrekk/androidsdk/MainActivity.kt @@ -94,8 +94,8 @@ class MainActivity : AppCompatActivity() { startActivity(Intent(this, CampaignActivity::class.java)) } - binding.formActivity.setOnClickListener { - val intent = Intent(this, FormActivity::class.java) + binding.btnWorkSchedulerTest.setOnClickListener { + val intent = Intent(this, WorkSchedulerTest::class.java) startActivity(intent) } @@ -267,8 +267,4 @@ class MainActivity : AppCompatActivity() { Webtrekk.getInstance().sendRequestsNowAndClean() } } - - override fun onNewIntent(intent: Intent?) { - super.onNewIntent(intent) - } } diff --git a/sample/src/main/java/com/example/webtrekk/androidsdk/WorkSchedulerTest.kt b/sample/src/main/java/com/example/webtrekk/androidsdk/WorkSchedulerTest.kt new file mode 100644 index 0000000..c391d76 --- /dev/null +++ b/sample/src/main/java/com/example/webtrekk/androidsdk/WorkSchedulerTest.kt @@ -0,0 +1,74 @@ +package com.example.webtrekk.androidsdk + +import android.content.Context +import android.os.Bundle +import android.util.Log +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.work.Constraints +import androidx.work.CoroutineWorker +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.WorkManager +import androidx.work.WorkerParameters +import com.example.webtrekk.androidsdk.databinding.ActivityWorkSchedulerTestBinding +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.withContext +import webtrekk.android.sdk.Webtrekk + +class WorkSchedulerTest : AppCompatActivity() { + + private val TAG = this::class.java.simpleName + private lateinit var binding: ActivityWorkSchedulerTestBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivityWorkSchedulerTestBinding.inflate(layoutInflater) + setContentView(binding.root) + ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets -> + val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) + insets + } + + binding.btnScheduleWorks.setOnClickListener { + val workCount = binding.etWorkCount.text.toString().toIntOrNull() ?: 0 + if (workCount > 0) { + for (i in 0 until workCount) { + Webtrekk.getInstance().sendRequestsNowAndClean() + //MyWorker.enqueue(this) + Log.d(TAG, "SCHEDULED WORK: ${i + 1}") + } + } + } + } +} + +internal class MyWorker(context: Context, workerParameters: WorkerParameters) : + CoroutineWorker(context, workerParameters) { + private val TAG = this::class.java.simpleName + private val dispatcher = Dispatchers.IO + override suspend fun doWork(): Result = coroutineScope { + return@coroutineScope withContext(dispatcher) { + Log.d(TAG, "WORK STARTED - ${id}") + delay(5000) + Result.success() + } + } + + companion object { + fun enqueue(context: Context) { + val constraints = Constraints.Builder() + .setRequiresCharging(true) + .build() + val work = OneTimeWorkRequestBuilder() + .setConstraints(constraints) + .build() + WorkManager.getInstance(context).enqueue(work) + } + } +} \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index 86b0352..4bb00d2 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -112,10 +112,10 @@ android:text="@string/web_view_activity" />