Skip to content

Commit b28297b

Browse files
authored
Merge pull request #48 from snabble/gradle_plugin
Gradle plugin support
2 parents 1869e20 + bcfde67 commit b28297b

File tree

23 files changed

+683
-68
lines changed

23 files changed

+683
-68
lines changed

build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ allprojects {
2929
repositories {
3030
google()
3131
mavenCentral()
32-
maven { url 'https://jitpack.io' }
3332
maven { url 'https://datatrans.jfrog.io/artifactory/mobile-sdk/' }
3433
}
3534

core/src/main/java/io/snabble/sdk/Config.kt

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import java.lang.Exception
1111
import java.lang.reflect.Type
1212
import java.util.concurrent.TimeUnit
1313

14+
/**
15+
* Configuration of the snabble SDK.
16+
*/
1417
data class Config (
1518
/**
1619
* The endpoint url of the snabble backend. For example "https://api.snabble.io" for the Production environment.
@@ -31,13 +34,12 @@ data class Config (
3134
var secret: String? = null,
3235

3336
/**
34-
* Relative path from the assets folder which points to a bundled file which contains the metadata
37+
* Relative path from the assets folder which points to a bundled file which contains the metadata.
3538
*
36-
*
37-
* This file gets initially used to initialize the sdk before network requests are made,
39+
* This file gets initially used to initialize the SDK before network requests are made,
3840
* or be able to use the sdk in the case of no network connection.
3941
*
40-
* Optional. If no file is specified every time the sdk is initialized we wait for a network response
42+
* Optional. If no path and no res id are specified every time the SDK is initialized we wait for a network response
4143
* from the backend.
4244
*
4345
* It is HIGHLY recommended to provide bundled metadata to allow the sdk to function
@@ -47,14 +49,19 @@ data class Config (
4749
var bundledMetadataAssetPath: String? = null,
4850

4951
/**
50-
* Optional. Used to override the versionName appended to the metadata url.
52+
* Resource id of the raw file which contains the metadata.
53+
*
54+
* This file gets initially used to initialize the SDK before network requests are made,
55+
* or be able to use the sdk in the case of no network connection.
5156
*
52-
* Defaults to the versionName in the app package.
57+
* Optional. If no res id and no path are specified every time the SDK is initialized we wait for a network response
58+
* from the backend.
5359
*
54-
* Must be in the format %d.%d
60+
* It is HIGHLY recommended to provide bundled metadata to allow the sdk to function
61+
* without having a network connection.
5562
*/
5663
@JvmField
57-
var versionName: String? = null,
64+
var bundledMetadataRawResId: Int = 0,
5865

5966
/**
6067
* If set to true, creates an full text index to support searching in the product database
@@ -89,21 +96,23 @@ data class Config (
8996
@JvmField
9097
var maxShoppingCartAge: Long = TimeUnit.HOURS.toMillis(4),
9198

92-
/** If set to true, disables certificate pinning */
99+
/** If set to true, disables certificate pinning. Not recommended for production! */
93100
@JvmField
94101
var disableCertificatePinning: Boolean = false,
95102

96-
/** SQL queries that will get executed in order on the product database */
103+
/** SQL queries that will get executed in order on the product database. */
97104
@JvmField
98105
var initialSQL: List<String> = emptyList(),
99106

100-
/** Vibrate while adding a product to the cart, by default false */
107+
/** Vibrate while adding a product to the cart, by default false. */
101108
@JvmField
102109
var vibrateToConfirmCartFilled: Boolean = false,
103110

104-
/** Set to true, to load shops that are marked as pre launch
111+
/**
112+
* Set to true, to load shops that are marked as pre launch
105113
* and are not part of the original metadata in the backend
106-
* (for example for testing shops in production before a go-live) */
114+
* (for example for testing shops in production before a go-live)
115+
*/
107116
@JvmField
108117
var loadActiveShops: Boolean = false,
109118

core/src/main/java/io/snabble/sdk/MetadataDownloader.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ import com.google.gson.JsonObject
55
import okhttp3.OkHttpClient
66
import io.snabble.sdk.utils.StringDownloader
77
import io.snabble.sdk.utils.GsonHolder
8-
import io.snabble.sdk.Snabble
98
import io.snabble.sdk.utils.Logger
109
import java.io.File
1110
import java.lang.Exception
1211

1312
@RestrictTo(RestrictTo.Scope.LIBRARY)
1413
internal class MetadataDownloader(
1514
okHttpClient: OkHttpClient?,
16-
bundledFileAssetPath: String?)
15+
bundledFileAssetPath: String?,
16+
bundledFileRawResId: Int)
1717
: StringDownloader(okHttpClient) {
1818
var hasData = false
1919
private set
@@ -22,8 +22,8 @@ internal class MetadataDownloader(
2222

2323
init {
2424
val storageFile = File(Snabble.internalStorageDirectory, "metadata_v2.json")
25-
if (bundledFileAssetPath != null) {
26-
setBundledData(Snabble.application, bundledFileAssetPath, storageFile)
25+
if (bundledFileAssetPath != null || bundledFileRawResId != 0) {
26+
setBundledData(Snabble.application, bundledFileAssetPath, bundledFileRawResId, storageFile)
2727
} else {
2828
setStorageFile(storageFile)
2929
}

core/src/main/java/io/snabble/sdk/OkHttpClientFactory.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ internal object OkHttpClientFactory {
4242
builder.cache(Cache(application.cacheDir, 10 * 1024 * 1024))
4343
builder.retryOnConnectionFailure(true)
4444
builder.pingInterval(5, TimeUnit.SECONDS) // workaround for https://github.com/square/okhttp/issues/3146
45-
builder.addInterceptor(OkHttpLogger(HttpLoggingInterceptor.Logger { message: String? ->
45+
builder.addInterceptor(OkHttpLogger { message: String? ->
4646
Logger.i(message)
47-
}))
47+
})
4848
Snabble.config.networkInterceptor?.let {
4949
builder.addNetworkInterceptor(it)
5050
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@file:JvmName("PropertiesExtensions")
2+
package io.snabble.sdk
3+
4+
import java.util.*
5+
6+
fun Properties.getBoolean(key: String, default: Boolean) =
7+
getProperty(key)?.toBooleanStrictOrNull() ?: default
8+
fun Properties.getLong(key: String, default: Long) =
9+
getProperty(key)?.toLongOrNull() ?: default
10+
fun Properties.getFloat(key: String, default: Float) =
11+
getProperty(key)?.toFloatOrNull() ?: default

core/src/main/java/io/snabble/sdk/Snabble.kt

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -359,16 +359,12 @@ object Snabble {
359359
return
360360
}
361361

362-
var version = this.config.versionName
363-
if (version == null) {
364-
version = try {
365-
val pInfo = application.packageManager.getPackageInfo(application.packageName, 0)
366-
pInfo?.versionName?.lowercase(Locale.ROOT)?.replace(" ", "") ?: "1.0"
367-
} catch (e: PackageManager.NameNotFoundException) {
368-
"1.0"
369-
}
362+
val version = try {
363+
val pInfo = application.packageManager.getPackageInfo(application.packageName, 0)
364+
pInfo?.versionName?.lowercase(Locale.ROOT)?.replace(" ", "") ?: "1.0"
365+
} catch (e: PackageManager.NameNotFoundException) {
366+
"1.0"
370367
}
371-
versionName = version
372368

373369
internalStorageDirectory = File(application.filesDir, "snabble/${this.config.appId}/")
374370
internalStorageDirectory.mkdirs()
@@ -392,9 +388,9 @@ object Snabble {
392388
this.config.lastSeenThreshold
393389
)
394390

395-
metadataDownloader = MetadataDownloader(okHttpClient, this.config.bundledMetadataAssetPath)
391+
metadataDownloader = MetadataDownloader(okHttpClient, this.config.bundledMetadataAssetPath, this.config.bundledMetadataRawResId)
396392

397-
if (this.config.bundledMetadataAssetPath != null) {
393+
if (this.config.bundledMetadataAssetPath != null || this.config.bundledMetadataRawResId != 0) {
398394
dispatchOnReady()
399395
} else {
400396
metadataDownloader.loadAsync(object : Downloader.Callback() {

core/src/main/java/io/snabble/sdk/SnabbleInitializer.kt

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,66 @@ package io.snabble.sdk
33
import android.app.Application
44
import android.content.Context
55
import android.content.pm.PackageManager
6+
import android.content.res.Resources
67
import androidx.startup.Initializer
78
import io.snabble.sdk.utils.Logger
89
import okhttp3.Interceptor
10+
import java.lang.IllegalStateException
11+
import java.util.*
912

1013
/**
1114
* Initializer for the snabble SDK using androidx.startup
1215
*/
1316
class SnabbleInitializer : Initializer<Snabble> {
1417
override fun create(context: Context): Snabble {
1518
val app = context.applicationContext as Application
19+
20+
// load properties created by the gradle plugin
21+
val env = UserPreferences(context).environment.name.lowercase()
22+
val resId = context.resources.getIdentifier("snabble_${env}_config", "raw", app.packageName)
23+
if (resId != Resources.ID_NULL) {
24+
val properties = Properties()
25+
properties.load(context.resources.openRawResource(resId))
26+
val config = Config().apply {
27+
appId = properties.getProperty("appId")
28+
endpointBaseUrl = properties.getProperty("endpointBaseUrl") ?: endpointBaseUrl
29+
secret = properties.getProperty("secret")
30+
val assetPath = properties.getProperty("bundledMetadataAssetPath")?.let { path ->
31+
if (context.resources.assets.list(path)?.isEmpty() != false) {
32+
null
33+
} else {
34+
path
35+
}
36+
}
37+
bundledMetadataAssetPath = assetPath
38+
bundledMetadataRawResId = context.resources.getIdentifier("snabble_${env}_metadata", "raw", app.packageName)
39+
generateSearchIndex = properties.getBoolean("generateSearchIndex", generateSearchIndex)
40+
maxProductDatabaseAge = properties.getLong("maxProductDatabaseAge", maxProductDatabaseAge)
41+
maxShoppingCartAge = properties.getLong("maxShoppingCartAge", maxShoppingCartAge)
42+
disableCertificatePinning = properties.getBoolean("disableCertificatePinning", disableCertificatePinning)
43+
vibrateToConfirmCartFilled = properties.getBoolean("vibrateToConfirmCartFilled", vibrateToConfirmCartFilled)
44+
loadActiveShops = properties.getBoolean("loadActiveShops", loadActiveShops)
45+
checkInRadius = properties.getFloat("checkInRadius", checkInRadius)
46+
checkOutRadius = properties.getFloat("checkOutRadius", checkOutRadius)
47+
lastSeenThreshold = properties.getLong("lastSeenThreshold", lastSeenThreshold)
48+
networkInterceptor =
49+
try {
50+
Class.forName(properties.getProperty("networkInterceptor", null))?.newInstance() as Interceptor?
51+
} catch (e: Throwable) {
52+
Logger.w("Could not instantiate network interceptor", e.message)
53+
null
54+
}
55+
manualProductDatabaseUpdates = properties.getBoolean("manualProductDatabaseUpdates", manualProductDatabaseUpdates)
56+
}
57+
58+
if (config.appId == null || config.secret == null) {
59+
throw IllegalStateException("Please file a bug report with our build.gradle file. This state should not be possible.")
60+
} else {
61+
Snabble.setup(app, config)
62+
return Snabble
63+
}
64+
}
65+
1666
val applicationInfo = app.packageManager.getApplicationInfo(app.packageName, PackageManager.GET_META_DATA)
1767
with(applicationInfo.metaData) {
1868
if (getBoolean("snabble_auto_initialization_disabled")) {
@@ -24,12 +74,10 @@ class SnabbleInitializer : Initializer<Snabble> {
2474
endpointBaseUrl = getString("snabble_endpoint_baseurl", endpointBaseUrl)
2575
secret = getString("snabble_secret", secret)
2676
bundledMetadataAssetPath = getString("snabble_bundled_metadata_asset_path", bundledMetadataAssetPath)
27-
versionName = getString("snabble_version_name", versionName)
2877
generateSearchIndex = getBoolean("snabble_generate_search_index", generateSearchIndex)
2978
maxProductDatabaseAge = getLong("snabble_max_product_database_age", maxProductDatabaseAge)
3079
maxShoppingCartAge = getLong("snabble_max_shopping_cart_age", maxShoppingCartAge)
3180
disableCertificatePinning = getBoolean("snabble_disable_certificate_pinning")
32-
initialSQL = getStringArrayList("snabble_initial_sql") ?: initialSQL
3381
vibrateToConfirmCartFilled = getBoolean("snabble_vibrate_to_confirm_cart_filled", vibrateToConfirmCartFilled)
3482
loadActiveShops = getBoolean("snabble_load_active_shops", loadActiveShops)
3583
checkInRadius = getFloat("snabble_check_in_radius", checkInRadius)
@@ -56,7 +104,5 @@ class SnabbleInitializer : Initializer<Snabble> {
56104
}
57105
}
58106

59-
override fun dependencies(): List<Class<out Initializer<*>>> {
60-
return emptyList()
61-
}
107+
override fun dependencies() = emptyList<Class<out Initializer<*>>>()
62108
}

core/src/main/java/io/snabble/sdk/UserPreferences.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class UserPreferences internal constructor(context: Context) {
4040
private const val SHARED_PREFERENCES_CONSENT_STATUS = "ConsentStatus"
4141
private const val SHARED_PREFERENCES_CONSENT_VERSION = "ConsentVersion"
4242
private const val SHARED_PREFERENCES_LAST_CHECKED_IN_SHOP = "lastShop"
43+
private const val SHARED_PREFERENCES_BASE_URL = "base_url"
4344

4445
@SuppressLint("SimpleDateFormat")
4546
private val BIRTHDAY_FORMAT = SimpleDateFormat("yyyy/MM/dd")
@@ -158,14 +159,27 @@ class UserPreferences internal constructor(context: Context) {
158159
* Does not contain any personalized information.
159160
*/
160161
var clientId: String?
161-
get() =
162-
sharedPreferences.getString(SHARED_PREFERENCES_CLIENT_ID, null)
162+
get() = sharedPreferences.getString(SHARED_PREFERENCES_CLIENT_ID, null)
163163
set(clientId) {
164164
sharedPreferences.edit()
165165
.putString(SHARED_PREFERENCES_CLIENT_ID, clientId)
166166
.apply()
167167
}
168168

169+
var environment: Environment
170+
get() = Environment.getEnvironmentByUrl(baseUrl)
171+
set(value) {
172+
baseUrl = value.baseUrl
173+
}
174+
175+
private var baseUrl: String
176+
get() = sharedPreferences.getString(SHARED_PREFERENCES_BASE_URL, null) ?: Environment.PRODUCTION.baseUrl
177+
set(value) {
178+
sharedPreferences.edit()
179+
.putString(SHARED_PREFERENCES_BASE_URL, value)
180+
.apply()
181+
}
182+
169183
internal var lastCheckedInShopId: String?
170184
@RestrictTo(RestrictTo.Scope.LIBRARY)
171185
get() =

java-sample/src/main/java/io/snabble/testapp/App.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,6 @@
1616
public class App extends Application {
1717
private static App instance;
1818

19-
private Project project;
20-
21-
public interface InitCallback {
22-
void done();
23-
24-
void error(String text);
25-
}
26-
2719
@Override
2820
public void onCreate() {
2921
super.onCreate();

java-sample/src/main/java/io/snabble/testapp/BaseActivity.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import android.view.KeyEvent;
66
import android.view.View;
77
import android.widget.ProgressBar;
8-
import android.widget.TextView;
98
import androidx.appcompat.app.AppCompatActivity;
109
import androidx.fragment.app.Fragment;
1110

@@ -14,24 +13,20 @@
1413
import io.snabble.sdk.ui.cart.ShoppingCartActivity;
1514
import io.snabble.sdk.ui.payment.PaymentCredentialsListActivity;
1615
import io.snabble.sdk.ui.payment.PaymentOptionsActivity;
16+
import io.snabble.sdk.ui.scanner.CombinedScannerActivity;
1717
import io.snabble.sdk.ui.scanner.SelfScanningActivity;
1818
import io.snabble.sdk.ui.utils.ZebraSupport;
1919
import io.snabble.sdk.ui.scanner.ProductResolver;
2020

2121
public abstract class BaseActivity extends AppCompatActivity {
2222

23-
private ProgressBar progressIndicator;
24-
private View content;
25-
private TextView sdkError;
26-
2723
@Override
2824
protected void onCreate(Bundle savedInstanceState) {
2925
super.onCreate(savedInstanceState);
3026
setContentView(R.layout.activity_main);
3127

32-
progressIndicator = findViewById(R.id.progress_indicator);
33-
content = findViewById(R.id.content);
34-
sdkError = findViewById(R.id.sdk_error);
28+
final ProgressBar progressIndicator = findViewById(R.id.progress_indicator);
29+
final View content = findViewById(R.id.content);
3530

3631
progressIndicator.setVisibility(View.GONE);
3732
content.setVisibility(View.VISIBLE);
@@ -69,6 +64,11 @@ public void showScanner() {
6964
startActivity(intent);
7065
}
7166

67+
public void showCombinedScanner() {
68+
Intent intent = new Intent(this, CombinedScannerActivity.class);
69+
startActivity(intent);
70+
}
71+
7272
public void showPaymentCredentialsList() {
7373
Intent intent = new Intent(this, PaymentCredentialsListActivity.class);
7474
startActivity(intent);

0 commit comments

Comments
 (0)