Development, Testing, and Sample App
This guide covers development best practices, testing strategies, and information about the Entrupy Android SDK sample application.
1. 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 11+
Project Configuration
1. Add Repository
Configure the GitHub Packages repository (and standard repositories) in your project:
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
url = uri("https://maven.pkg.github.com/entrupy/entrupy-sdk-android")
credentials {
username = System.getenv("GITHUB_USER")
password = System.getenv("GITHUB_TOKEN")
}
}
}
}
2. Add Dependencies
// app/build.gradle.kts
dependencies {
implementation("com.entrupy:sdk:2.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-feature android:name="android.hardware.camera.any" />
2. Testing Strategies
1. Unit Testing
Test your SDK integration logic independently:
import com.entrupy.sdk.app.EntrupyApp
import com.entrupy.sdk.model.ConfigMetadata
import com.entrupy.sdk.model.METADATA_KEY_BRAND
import com.entrupy.sdk.model.METADATA_KEY_ITEM_TYPE
import com.entrupy.sdk.model.METADATA_KEY_CUSTOMER_ITEM_ID
import com.entrupy.sdk.model.configMetadataOf
// Example unit test
class EntrupyAppTest {
@Test
fun testUserAuthorization() {
// Mock SDK responses
val mockApp = mock<EntrupyApp>()
whenever(mockApp.generateSDKAuthorizationRequest()).thenReturn("test_request")
// Test authorization flow
val authRequest = mockApp.generateSDKAuthorizationRequest()
assertEquals("test_request", authRequest)
}
@Test
fun testConfigMetadataValidation() {
val validMetadata = configMetadataOf(
METADATA_KEY_BRAND to "Nike",
METADATA_KEY_ITEM_TYPE to "Sneakers",
METADATA_KEY_CUSTOMER_ITEM_ID to "test_123"
)
assertTrue(isValidMetadata(validMetadata))
// Test with all required fields
val minimalMetadata = configMetadataOf(
METADATA_KEY_BRAND to "Gucci",
METADATA_KEY_ITEM_TYPE to "Handbag",
METADATA_KEY_CUSTOMER_ITEM_ID to "ITEM-001"
)
assertTrue(isValidMetadata(minimalMetadata))
}
}
2. Integration Testing
Test the complete flow with your backend:
import com.entrupy.sdk.app.EntrupyApp
import com.entrupy.sdk.listeners.SdkLoginCallback
// Example integration test
@RunWith(AndroidJUnit4::class)
class EntrupyIntegrationTest {
@Test
fun testCompleteAuthenticationFlow() {
// 1. Initialize SDK
EntrupyApp.init(ApplicationProvider.getApplicationContext())
// 2. Authorize user
val entrupyApp = EntrupyApp.sharedInstance()
val authRequest = entrupyApp.generateSDKAuthorizationRequest()
val signedRequest = callBackendForAuthorization(authRequest)
// 3. Login to SDK
var loginSuccess = false
entrupyApp.loginUser(signedRequest, object : SdkLoginCallback {
override fun onLoginStarted() {
Log.d("Test", "Login started")
}
override fun onLoginSuccess(expirationTime: Long) {
loginSuccess = true
}
override fun onLoginError(
errorCode: Int,
description: String,
localizedDescription: String
) {
fail("Login failed: $description")
}
})
// 4. Verify authorization
assertTrue(entrupyApp.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
)
}
}
3. Sample Application
Entrupy provides a comprehensive sample Android application to help developers understand how to integrate the Entrupy SDK into their own projects.
For a complete working example, see entrupy-sdk-sampleproject-android.
Understanding the Integration via Git History
The sample project is designed to help you understand exactly what changes are required to integrate the Entrupy SDK into your Android application. Navigate to the "Entrupy SDK Integration" commit in the repository's Git history to see a focused diff containing only the changes necessary for SDK integration—without any unrelated project setup or boilerplate code.
This approach allows you to:
- See the exact files that need to be modified
- Understand the minimal code changes required
- Copy relevant snippets directly into your own project
- Compare your implementation against a working reference
Features Demonstrated
-
Complete Integration Flow
- SDK initialization
- User authorization
- Capture flow integration
- Result handling
-
Best Practices
- Error handling
- Session management
- UI/UX patterns
- Backend integration
-
Advanced Features
- Custom UI theming
- Multi-language support
- Offline handling
- Analytics integration
Running the Sample App
-
Clone the Repository
git clone https://github.com/entrupy/entrupy-sdk-sampleproject-android.git
cd entrupy-sdk-sampleproject-android -
Configure GitHub Packages Authentication
Add your GitHub credentials to
~/.gradle/gradle.properties:gpr.user=YOUR_GITHUB_USERNAME
gpr.token=YOUR_GITHUB_PERSONAL_ACCESS_TOKEN -
Configure Sample App
- Update the backend URL configuration as needed
- Add your Entrupy credentials to
local.properties
-
Run the App
./gradlew assembleDebug
Key Sample App Components
| File | Role |
|---|---|
EntrupySampleApplication.kt | Calls EntrupyApp.init() with the Application context. |
MainActivity.kt | App entry point; hosts navigation into the demo flows. |
MainScreen.kt | Full integration demo: authorization, capture, and history. |
PartnerApi.kt / PartnerApiClient.kt | Retrofit-style definitions and client for your partner backend (signing auth requests, status, and related calls). |
4. Development Best Practices
1. Error Handling
import com.entrupy.sdk.listeners.EntrupyErrorCode
// Centralized error handling
object ErrorHandler {
fun handleSDKError(errorCode: Int, description: String) {
when (errorCode) {
EntrupyErrorCode.UNAUTHORIZED_ACCESS -> {
// Re-authorize user
reauthorizeUser()
}
EntrupyErrorCode.TOO_MANY_REQUESTS -> {
// Handle rate limiting
handleRateLimit()
}
EntrupyErrorCode.SERVICE_UNAVAILABLE -> {
// Show service unavailable error
showServiceUnavailable()
}
else -> {
// Log and show generic error
Log.e("Entrupy", "Error: $errorCode - $description")
showGenericError()
}
}
}
}
2. Logging
// Structured logging
object EntrupyLogger {
private const val TAG = "EntrupyApp"
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
}
}
5. Debugging Tips
1. Enable Debug Logging
// Enable detailed logging in debug builds
if (BuildConfig.DEBUG) {
// SDK logging is enabled by default in debug builds
Log.d("Entrupy", "Debug mode enabled")
}
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")
}