Skip to main content

Development, Testing, and Sample App

This guide covers development best practices, testing strategies, and information about the Entrupy Android SDK sample application.

Development Environment Setup

Prerequisites

  • Android Studio: Latest stable version (recommended: Android Studio Hedgehog or newer)
  • Android SDK: API level 24+ (Android 7.0 Nougat)
  • Gradle: Version 7.0+ (recommended: 8.0+)
  • Kotlin: Version 1.5+ (recommended: 1.9+)
  • Java: Version 8+ (if using Java instead of Kotlin)

Project Configuration

1. Add Repository

Ensure Maven Central is included in your project's repository configuration:

// settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}

2. Add Dependencies

// app/build.gradle.kts
dependencies {
implementation("com.entrupy:sdk:1.0.0")

// Optional: For testing
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}

3. Configure Permissions

The SDK automatically handles permission requests, but ensure your app's manifest includes:

<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

<uses-feature android:name="android.hardware.camera.any" />

Testing Strategies

1. Unit Testing

Test your SDK integration logic independently:

// Example unit test
class EntrupySDKTest {

@Test
fun testUserAuthorization() {
// Mock SDK responses
val mockSdk = mock<EntrupySdk>()
whenever(mockSdk.generateAuthorizationRequest()).thenReturn("test_request")

// Test authorization flow
val authRequest = mockSdk.generateAuthorizationRequest()
assertEquals("test_request", authRequest)
}

@Test
fun testMetadataValidation() {
val validMetadata = mapOf(
"brand" to "Nike",
"style_name" to "Air Jordan 1",
"customer_item_id" to "test_123"
)

assertTrue(isValidMetadata(validMetadata))

val invalidMetadata = mapOf(
"brand" to "Nike"
// Missing required fields
)

assertFalse(isValidMetadata(invalidMetadata))
}
}

2. Integration Testing

Test the complete flow with your backend:

// Example integration test
@RunWith(AndroidJUnit4::class)
class EntrupyIntegrationTest {

@Test
fun testCompleteAuthenticationFlow() {
// 1. Initialize SDK
Entrupy.init(ApplicationProvider.getApplicationContext(), "test_api_key")

// 2. Authorize user
val authRequest = EntrupySdk.getInstance().generateAuthorizationRequest()
val signedRequest = callBackendForAuthorization(authRequest)

// 3. Login to SDK
var loginSuccess = false
EntrupySdk.getInstance().login(signedRequest, object : EntrupyLoginCallback {
override fun onSuccess(expirationTimestamp: Long) {
loginSuccess = true
}

override fun onFailure(errorCode: EntrupyErrorCode, message: String) {
fail("Login failed: $message")
}
})

// 4. Verify authorization
assertTrue(EntrupySdk.getInstance().isAuthorizationValid())

// 5. Test capture flow (if needed)
// Note: This would require a real device or emulator with camera
}
}

3. UI Testing

Test the user interface components:

@RunWith(AndroidJUnit4::class)
class EntrupyUITest {

@get:Rule
val activityRule = ActivityScenarioRule(MainActivity::class.java)

@Test
fun testCaptureFlowLaunch() {
// Navigate to capture button
onView(withId(R.id.btn_start_capture))
.perform(click())

// Verify capture flow is launched
// Note: This would require custom assertions based on your UI
}

@Test
fun testPermissionHandling() {
// Test permission denial flow
// This requires special setup to simulate permission denial
}
}

4. Mock Backend for Testing

Create a mock backend for development and testing:

// Mock backend implementation
class MockEntrupyBackend {

fun authorizeUser(sdkRequest: String): String {
// Return a mock signed request
return "mock_signed_request_${System.currentTimeMillis()}"
}

fun getItemStatus(customerItemId: String): ItemStatus {
return ItemStatus(
customerItemId = customerItemId,
status = "completed",
result = mapOf("authenticity" to "authentic"),
eta = null
)
}
}

Sample Application

The Entrupy Android SDK includes a comprehensive sample application that demonstrates:

Features Demonstrated

  1. Complete Integration Flow

    • SDK initialization
    • User authorization
    • Capture flow integration
    • Result handling
  2. Best Practices

    • Error handling
    • Session management
    • UI/UX patterns
    • Backend integration
  3. Advanced Features

    • Custom UI theming
    • Multi-language support
    • Offline handling
    • Analytics integration

Sample App Structure

sample-app/
├── app/
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/com/entrupy/sample/
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── AuthActivity.kt
│ │ │ │ ├── CaptureActivity.kt
│ │ │ │ ├── ResultActivity.kt
│ │ │ │ ├── network/
│ │ │ │ │ ├── ApiService.kt
│ │ │ │ │ └── RetrofitClient.kt
│ │ │ │ └── utils/
│ │ │ │ ├── EntrupyManager.kt
│ │ │ │ └── SessionManager.kt
│ │ │ └── res/
│ │ │ ├── layout/
│ │ │ ├── values/
│ │ │ └── drawable/
│ │ └── test/
│ └── build.gradle.kts
├── backend/
│ ├── server.js
│ ├── package.json
│ └── README.md
└── README.md

Running the Sample App

  1. Clone the Repository

    git clone https://github.com/entrupy/android-sdk-sample.git
    cd android-sdk-sample
  2. Setup Backend

    cd backend
    npm install
    npm start
  3. Configure Sample App

    • Update ApiService.kt with your backend URL
    • Add your Entrupy API key to local.properties
  4. Run the App

    cd ..
    ./gradlew assembleDebug

Key Sample App Components

EntrupyManager.kt

class EntrupyManager private constructor() {

companion object {
@Volatile
private var INSTANCE: EntrupyManager? = null

fun getInstance(): EntrupyManager {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: EntrupyManager().also { INSTANCE = it }
}
}
}

fun initialize(context: Context) {
Entrupy.init(context, BuildConfig.ENTRUPY_API_KEY)
}

fun authorizeUser(callback: (Boolean) -> Unit) {
// Implementation of authorization flow
}

fun startCapture(activity: Activity, metadata: Map<String, String>) {
// Implementation of capture flow
}
}

SessionManager.kt

class SessionManager(context: Context) {

private val sharedPrefs = context.getSharedPreferences("entrupy_session", Context.MODE_PRIVATE)

fun saveTokenExpiry(expiryTimestamp: Long) {
sharedPrefs.edit()
.putLong("token_expiry", expiryTimestamp)
.apply()
}

fun isTokenValid(): Boolean {
val expiry = sharedPrefs.getLong("token_expiry", 0L)
return System.currentTimeMillis() < (expiry - 60_000) // 1-minute buffer
}

fun clearSession() {
sharedPrefs.edit().clear().apply()
EntrupySdk.getInstance().logout()
}
}

Development Best Practices

1. Error Handling

// Centralized error handling
object ErrorHandler {

fun handleSDKError(errorCode: EntrupyErrorCode, message: String) {
when (errorCode) {
EntrupyErrorCode.AUTHORIZATION_EXPIRED -> {
// Re-authorize user
reauthorizeUser()
}
EntrupyErrorCode.NETWORK_ERROR -> {
// Show network error
showNetworkError()
}
else -> {
// Log and show generic error
Log.e("Entrupy", "Error: $errorCode - $message")
showGenericError()
}
}
}
}

2. Logging

// Structured logging
object EntrupyLogger {

private const val TAG = "EntrupySDK"

fun logEvent(event: String, properties: Map<String, Any> = emptyMap()) {
Log.d(TAG, "Event: $event, Properties: $properties")
// Send to analytics service
}

fun logError(error: Throwable, context: String = "") {
Log.e(TAG, "Error in $context", error)
// Send to crash reporting service
}
}

3. Configuration Management

// Environment-specific configuration
object Config {

const val API_BASE_URL = "https://api.entrupy.com"
const val WEBHOOK_URL = "https://your-backend.com/webhooks"

// Environment-specific settings
object Environment {
const val PRODUCTION = "production"
const val STAGING = "staging"
const val DEVELOPMENT = "development"
}

val currentEnvironment = if (BuildConfig.DEBUG) {
Environment.DEVELOPMENT
} else {
Environment.PRODUCTION
}
}

Debugging Tips

1. Enable Debug Logging

// Enable detailed logging in debug builds
if (BuildConfig.DEBUG) {
EntrupySdk.getInstance().setDebugMode(true)
}

2. Network Inspection

Use tools like Charles Proxy or Flipper to inspect network requests:

// Add network interceptor for debugging
OkHttpClient.Builder()
.addInterceptor { chain ->
val request = chain.request()
Log.d("Network", "Request: ${request.url}")
val response = chain.proceed(request)
Log.d("Network", "Response: ${response.code}")
response
}
.build()

3. UI Inspection

Use Android Studio's Layout Inspector to debug UI issues:

// Add debug information to views
if (BuildConfig.DEBUG) {
view.setTag(R.id.debug_tag, "entrupy_capture_button")
}