Mobile Articles / Blogs / Perficient https://blogs.perficient.com/tag/mobile/ Expert Digital Insights Thu, 10 Apr 2025 22:46:00 +0000 en-US hourly 1 https://blogs.perficient.com/files/favicon-194x194-1-150x150.png Mobile Articles / Blogs / Perficient https://blogs.perficient.com/tag/mobile/ 32 32 30508587 Android Development Codelab: Mastering Advanced Concepts https://blogs.perficient.com/2025/04/10/android-development-codelab-mastering-advanced-concepts/ https://blogs.perficient.com/2025/04/10/android-development-codelab-mastering-advanced-concepts/#respond Thu, 10 Apr 2025 22:28:06 +0000 https://blogs.perficient.com/?p=379698

 

This guide will walk you through building a small application step-by-step, focusing on integrating several powerful tools and concepts essential for modern Android development.

What We’ll Cover:

  • Jetpack Compose: Building the UI declaratively.
  • NoSQL Database (Firestore): Storing and retrieving data in the cloud.
  • WorkManager: Running reliable background tasks.
  • Build Flavors: Creating different versions of the app (e.g., dev vs. prod).
  • Proguard/R8: Shrinking and obfuscating your code for release.
  • Firebase App Distribution: Distributing test builds easily.
  • CI/CD (GitHub Actions): Automating the build and distribution process.

The Goal: Build a “Task Reporter” app. Users can add simple task descriptions. These tasks are saved to Firestore. A background worker will periodically “report” (log a message or update a counter in Firestore) that the app is active. We’ll have dev and prod flavors pointing to different Firestore collections/data and distribute the dev build for testing.

Prerequisites:

  • Android Studio (latest stable version recommended).
  • Basic understanding of Kotlin and Android development fundamentals.
  • Familiarity with Jetpack Compose basics (Composable functions, State).
  • A Google account to use Firebase.
  • A GitHub account (for CI/CD).

Let’s get started!


Step 0: Project Setup

  1. Create New Project: Open Android Studio -> New Project -> Empty Activity (choose Compose).
  2. Name: AdvancedConceptsApp (or your choice).
  3. Package Name: Your preferred package name (e.g., com.yourcompany.advancedconceptsapp).
  4. Language: Kotlin.
  5. Minimum SDK: API 24 or higher.
  6. Build Configuration Language: Kotlin DSL (build.gradle.kts).
  7. Click Finish.

Step 1: Firebase Integration (Firestore & App Distribution)

  1. Connect to Firebase: In Android Studio: Tools -> Firebase.
    • In the Assistant panel, find Firestore. Click “Get Started with Cloud Firestore”. Click “Connect to Firebase”. Follow the prompts to create a new Firebase project or connect to an existing one.
    • Click “Add Cloud Firestore to your app”. Accept changes to your build.gradle.kts (or build.gradle) files. This adds the necessary dependencies.
    • Go back to the Firebase Assistant, find App Distribution. Click “Get Started”. Add the App Distribution Gradle plugin by clicking the button. Accept changes.
  2. Enable Services in Firebase Console:
    • Go to the Firebase Console and select your project.
    • Enable Firestore Database (start in Test mode).
    • In the left menu, go to Build -> Firestore Database. Click “Create database”.
      • Start in Test mode for easier initial development (we’ll secure it later if needed). Choose a location close to your users. Click “Enable”.
    • Ensure App Distribution is accessible (no setup needed here yet).
  3. Download Initial google-services.json:
    • In Firebase Console -> Project Settings (gear icon) -> Your apps.
    • Ensure your Android app (using the base package name like com.yourcompany.advancedconceptsapp) is registered. If not, add it.
    • Download the google-services.json file.
    • Switch Android Studio to the Project view and place the file inside the app/ directory.
    • Note: We will likely replace this file in Step 4 after configuring build flavors.

Step 2: Building the Basic UI with Compose

Let’s create a simple UI to add and display tasks.

  1. Dependencies: Ensure necessary dependencies for Compose, ViewModel, Firestore, and WorkManager are in app/build.gradle.kts.
    app/build.gradle.kts

    
    dependencies {
        // Core & Lifecycle & Activity
        implementation("androidx.core:core-ktx:1.13.1") // Use latest versions
        implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.1")
        implementation("androidx.activity:activity-compose:1.9.0")
        // Compose
        implementation(platform("androidx.compose:compose-bom:2024.04.01")) // Check latest BOM
        implementation("androidx.compose.ui:ui")
        implementation("androidx.compose.ui:ui-graphics")
        implementation("androidx.compose.ui:ui-tooling-preview")
        implementation("androidx.compose.material3:material3")
        implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.1")
        // Firebase
        implementation(platform("com.google.firebase:firebase-bom:33.0.0")) // Check latest BOM
        implementation("com.google.firebase:firebase-firestore-ktx")
        // WorkManager
        implementation("androidx.work:work-runtime-ktx:2.9.0") // Check latest version
    }
                    

    Sync Gradle files.

  2. Task Data Class: Create data/Task.kt.
    data/Task.kt

    
    package com.yourcompany.advancedconceptsapp.data
    
    import com.google.firebase.firestore.DocumentId
    
    data class Task(
        @DocumentId
        val id: String = "",
        val description: String = "",
        val timestamp: Long = System.currentTimeMillis()
    ) {
        constructor() : this("", "", 0L) // Firestore requires a no-arg constructor
    }
                    
  3. ViewModel: Create ui/TaskViewModel.kt. (We’ll update the collection name later).
    ui/TaskViewModel.kt

    
    package com.yourcompany.advancedconceptsapp.ui
    
    import androidx.lifecycle.ViewModel
    import androidx.lifecycle.viewModelScope
    import com.google.firebase.firestore.ktx.firestore
    import com.google.firebase.firestore.ktx.toObjects
    import com.google.firebase.ktx.Firebase
    import com.yourcompany.advancedconceptsapp.data.Task
    // Import BuildConfig later when needed
    import kotlinx.coroutines.flow.MutableStateFlow
    import kotlinx.coroutines.flow.StateFlow
    import kotlinx.coroutines.launch
    import kotlinx.coroutines.tasks.await
    
    // Temporary placeholder - will be replaced by BuildConfig field
    const val TEMPORARY_TASKS_COLLECTION = "tasks"
    
    class TaskViewModel : ViewModel() {
        private val db = Firebase.firestore
        // Use temporary constant for now
        private val tasksCollection = db.collection(TEMPORARY_TASKS_COLLECTION)
    
        private val _tasks = MutableStateFlow<List<Task>>(emptyList())
        val tasks: StateFlow<List<Task>> = _tasks
    
        private val _error = MutableStateFlow<String?>(null)
        val error: StateFlow<String?> = _error
    
        init {
            loadTasks()
        }
    
        fun loadTasks() {
            viewModelScope.launch {
                try {
                     tasksCollection.orderBy("timestamp", com.google.firebase.firestore.Query.Direction.DESCENDING)
                        .addSnapshotListener { snapshots, e ->
                            if (e != null) {
                                _error.value = "Error listening: ${e.localizedMessage}"
                                return@addSnapshotListener
                            }
                            _tasks.value = snapshots?.toObjects<Task>() ?: emptyList()
                            _error.value = null
                        }
                } catch (e: Exception) {
                    _error.value = "Error loading: ${e.localizedMessage}"
                }
            }
        }
    
         fun addTask(description: String) {
            if (description.isBlank()) {
                _error.value = "Task description cannot be empty."
                return
            }
            viewModelScope.launch {
                 try {
                     val task = Task(description = description, timestamp = System.currentTimeMillis())
                     tasksCollection.add(task).await()
                     _error.value = null
                 } catch (e: Exception) {
                    _error.value = "Error adding: ${e.localizedMessage}"
                }
            }
        }
    }
                    
  4. Main Screen Composable: Create ui/TaskScreen.kt.
    ui/TaskScreen.kt

    
    package com.yourcompany.advancedconceptsapp.ui
    
    // Imports: androidx.compose.*, androidx.lifecycle.viewmodel.compose.viewModel, java.text.SimpleDateFormat, etc.
    import androidx.compose.foundation.layout.*
    import androidx.compose.foundation.lazy.LazyColumn
    import androidx.compose.foundation.lazy.items
    import androidx.compose.material3.*
    import androidx.compose.runtime.*
    import androidx.compose.ui.Alignment
    import androidx.compose.ui.Modifier
    import androidx.compose.ui.unit.dp
    import androidx.lifecycle.viewmodel.compose.viewModel
    import com.yourcompany.advancedconceptsapp.data.Task
    import java.text.SimpleDateFormat
    import java.util.Date
    import java.util.Locale
    import androidx.compose.ui.res.stringResource
    import com.yourcompany.advancedconceptsapp.R // Import R class
    
    @OptIn(ExperimentalMaterial3Api::class) // For TopAppBar
    @Composable
    fun TaskScreen(taskViewModel: TaskViewModel = viewModel()) {
        val tasks by taskViewModel.tasks.collectAsState()
        val errorMessage by taskViewModel.error.collectAsState()
        var taskDescription by remember { mutableStateOf("") }
    
        Scaffold(
            topBar = {
                TopAppBar(title = { Text(stringResource(id = R.string.app_name)) }) // Use resource for flavor changes
            }
        ) { paddingValues ->
            Column(modifier = Modifier.padding(paddingValues).padding(16.dp).fillMaxSize()) {
                // Input Row
                Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
                    OutlinedTextField(
                        value = taskDescription,
                        onValueChange = { taskDescription = it },
                        label = { Text("New Task Description") },
                        modifier = Modifier.weight(1f),
                        singleLine = true
                    )
                    Spacer(modifier = Modifier.width(8.dp))
                    Button(onClick = {
                        taskViewModel.addTask(taskDescription)
                        taskDescription = ""
                    }) { Text("Add") }
                }
                Spacer(modifier = Modifier.height(16.dp))
                // Error Message
                errorMessage?.let { Text(it, color = MaterialTheme.colorScheme.error, modifier = Modifier.padding(bottom = 8.dp)) }
                // Task List
                if (tasks.isEmpty() && errorMessage == null) {
                    Text("No tasks yet. Add one!")
                } else {
                    LazyColumn(modifier = Modifier.weight(1f)) {
                        items(tasks, key = { it.id }) { task ->
                            TaskItem(task)
                            Divider()
                        }
                    }
                }
            }
        }
    }
    
    @Composable
    fun TaskItem(task: Task) {
        val dateFormat = remember { SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()) }
        Row(modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp), verticalAlignment = Alignment.CenterVertically) {
            Column(modifier = Modifier.weight(1f)) {
                Text(task.description, style = MaterialTheme.typography.bodyLarge)
                Text("Added: ${dateFormat.format(Date(task.timestamp))}", style = MaterialTheme.typography.bodySmall)
            }
        }
    }
                    
  5. Update MainActivity.kt: Set the content to TaskScreen.
    MainActivity.kt

    
    package com.yourcompany.advancedconceptsapp
    
    import android.os.Bundle
    import androidx.activity.ComponentActivity
    import androidx.activity.compose.setContent
    import androidx.compose.foundation.layout.fillMaxSize
    import androidx.compose.material3.MaterialTheme
    import androidx.compose.material3.Surface
    import androidx.compose.ui.Modifier
    import com.yourcompany.advancedconceptsapp.ui.TaskScreen
    import com.yourcompany.advancedconceptsapp.ui.theme.AdvancedConceptsAppTheme
    // Imports for WorkManager scheduling will be added in Step 3
    
    class MainActivity : ComponentActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContent {
                AdvancedConceptsAppTheme {
                    Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
                        TaskScreen()
                    }
                }
            }
            // TODO: Schedule WorkManager job in Step 3
        }
    }
                    
  6. Run the App: Test basic functionality. Tasks should appear and persist in Firestore’s `tasks` collection (initially).

Step 3: WorkManager Implementation

Create a background worker for periodic reporting.

  1. Create the Worker: Create worker/ReportingWorker.kt. (Collection name will be updated later).
    worker/ReportingWorker.kt

    
    package com.yourcompany.advancedconceptsapp.worker
    
    import android.content.Context
    import android.util.Log
    import androidx.work.CoroutineWorker
    import androidx.work.WorkerParameters
    import com.google.firebase.firestore.ktx.firestore
    import com.google.firebase.ktx.Firebase
    // Import BuildConfig later when needed
    import kotlinx.coroutines.tasks.await
    
    // Temporary placeholder - will be replaced by BuildConfig field
    const val TEMPORARY_USAGE_LOG_COLLECTION = "usage_logs"
    
    class ReportingWorker(appContext: Context, workerParams: WorkerParameters) :
        CoroutineWorker(appContext, workerParams) {
    
        companion object { const val TAG = "ReportingWorker" }
        private val db = Firebase.firestore
    
        override suspend fun doWork(): Result {
            Log.d(TAG, "Worker started: Reporting usage.")
            return try {
                val logEntry = hashMapOf(
                    "timestamp" to System.currentTimeMillis(),
                    "message" to "App usage report.",
                    "worker_run_id" to id.toString()
                )
                // Use temporary constant for now
                db.collection(TEMPORARY_USAGE_LOG_COLLECTION).add(logEntry).await()
                Log.d(TAG, "Worker finished successfully.")
                Result.success()
            } catch (e: Exception) {
                Log.e(TAG, "Worker failed", e)
                Result.failure()
            }
        }
    }
                    
  2. Schedule the Worker: Update MainActivity.kt‘s onCreate method.
    MainActivity.kt additions

    
    // Add these imports to MainActivity.kt
    import android.content.Context
    import android.util.Log
    import androidx.work.*
    import com.yourcompany.advancedconceptsapp.worker.ReportingWorker
    import java.util.concurrent.TimeUnit
    
    // Inside MainActivity class, after setContent { ... } block in onCreate
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            // ... existing code ...
        }
        // Schedule the worker
        schedulePeriodicUsageReport(this)
    }
    
    // Add this function to MainActivity class
    private fun schedulePeriodicUsageReport(context: Context) {
        val constraints = Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .build()
    
        val reportingWorkRequest = PeriodicWorkRequestBuilder<ReportingWorker>(
                1, TimeUnit.HOURS // ~ every hour
             )
            .setConstraints(constraints)
            .addTag(ReportingWorker.TAG)
            .build()
    
        WorkManager.getInstance(context).enqueueUniquePeriodicWork(
            ReportingWorker.TAG,
            ExistingPeriodicWorkPolicy.KEEP,
            reportingWorkRequest
        )
        Log.d("MainActivity", "Periodic reporting work scheduled.")
    }
                    
  3. Test WorkManager:
    • Run the app. Check Logcat for messages from ReportingWorker and MainActivity about scheduling.
    • WorkManager tasks don’t run immediately, especially periodic ones. You can use ADB commands to force execution for testing:
      • Find your package name: com.yourcompany.advancedconceptsapp
      • Force run jobs: adb shell cmd jobscheduler run -f com.yourcompany.advancedconceptsapp 999 (The 999 is usually sufficient, it’s a job ID).
      • Or use Android Studio’s App Inspection tab -> Background Task Inspector to view and trigger workers.
    • Check your Firestore Console for the usage_logs collection.

Step 4: Build Flavors (dev vs. prod)

Create dev and prod flavors for different environments.

  1. Configure app/build.gradle.kts:
    app/build.gradle.kts

    
    android {
        // ... namespace, compileSdk, defaultConfig ...
    
        // ****** Enable BuildConfig generation ******
        buildFeatures {
            buildConfig = true
        }
        // *******************************************
    
        flavorDimensions += "environment"
    
        productFlavors {
            create("dev") {
                dimension = "environment"
                applicationIdSuffix = ".dev" // CRITICAL: Changes package name for dev builds
                versionNameSuffix = "-dev"
                resValue("string", "app_name", "Task Reporter (Dev)")
                buildConfigField("String", "TASKS_COLLECTION", "\"tasks_dev\"")
                buildConfigField("String", "USAGE_LOG_COLLECTION", "\"usage_logs_dev\"")
            }
            create("prod") {
                dimension = "environment"
                resValue("string", "app_name", "Task Reporter")
                buildConfigField("String", "TASKS_COLLECTION", "\"tasks\"")
                buildConfigField("String", "USAGE_LOG_COLLECTION", "\"usage_logs\"")
            }
        }
    
        // ... buildTypes, compileOptions, etc ...
    }
                    

    Sync Gradle files.

    Important: We added applicationIdSuffix = ".dev". This means the actual package name for your development builds will become something like com.yourcompany.advancedconceptsapp.dev. This requires an update to your Firebase project setup, explained next. Also note the buildFeatures { buildConfig = true } block which is required to use buildConfigField.
  2. Handling Firebase for Suffixed Application IDs

    Because the `dev` flavor now has a different application ID (`…advancedconceptsapp.dev`), the original `google-services.json` file (downloaded in Step 1) will not work for `dev` builds, causing a “No matching client found” error during build.

    You must add this new Application ID to your Firebase project:

    1. Go to Firebase Console: Open your project settings (gear icon).
    2. Your apps: Scroll down to the “Your apps” card.
    3. Add app: Click “Add app” and select the Android icon (</>).
    4. Register dev app:
      • Package name: Enter the exact suffixed ID: com.yourcompany.advancedconceptsapp.dev (replace `com.yourcompany.advancedconceptsapp` with your actual base package name).
      • Nickname (Optional): “Task Reporter Dev”.
      • SHA-1 (Optional but Recommended): Add the debug SHA-1 key from `./gradlew signingReport`.
    5. Register and Download: Click “Register app”. Crucially, download the new google-services.json file offered. This file now contains configurations for BOTH your base ID and the `.dev` suffixed ID.
    6. Replace File: In Android Studio (Project view), delete the old google-services.json from the app/ directory and replace it with the **newly downloaded** one.
    7. Skip SDK steps: You can skip the remaining steps in the Firebase console for adding the SDK.
    8. Clean & Rebuild: Back in Android Studio, perform a Build -> Clean Project and then Build -> Rebuild Project.
    Now your project is correctly configured in Firebase for both `dev` (with the `.dev` suffix) and `prod` (base package name) variants using a single `google-services.json`.
  3. Create Flavor-Specific Source Sets:
    • Switch to Project view in Android Studio.
    • Right-click on app/src -> New -> Directory. Name it dev.
    • Inside dev, create res/values/ directories.
    • Right-click on app/src -> New -> Directory. Name it prod.
    • Inside prod, create res/values/ directories.
    • (Optional but good practice): You can now move the default app_name string definition from app/src/main/res/values/strings.xml into both app/src/dev/res/values/strings.xml and app/src/prod/res/values/strings.xml. Or, you can rely solely on the resValue definitions in Gradle (as done above). Using resValue is often simpler for single strings like app_name. If you had many different resources (layouts, drawables), you’d put them in the respective dev/res or prod/res folders.
  4. Use Build Config Fields in Code:
      • Update TaskViewModel.kt and ReportingWorker.kt to use BuildConfig instead of temporary constants.

    TaskViewModel.kt change

    
    // Add this import
    import com.yourcompany.advancedconceptsapp.BuildConfig
    
    // Replace the temporary constant usage
    // const val TEMPORARY_TASKS_COLLECTION = "tasks" // Remove this line
    private val tasksCollection = db.collection(BuildConfig.TASKS_COLLECTION) // Use build config field
                        

    ReportingWorker.kt change

    
    // Add this import
    import com.yourcompany.advancedconceptsapp.BuildConfig
    
    // Replace the temporary constant usage
    // const val TEMPORARY_USAGE_LOG_COLLECTION = "usage_logs" // Remove this line
    
    // ... inside doWork() ...
    db.collection(BuildConfig.USAGE_LOG_COLLECTION).add(logEntry).await() // Use build config field
                        

    Modify TaskScreen.kt to potentially use the flavor-specific app name (though resValue handles this automatically if you referenced @string/app_name correctly, which TopAppBar usually does). If you set the title directly, you would load it from resources:

     // In TaskScreen.kt (if needed)
    import androidx.compose.ui.res.stringResource
    import com.yourcompany.advancedconceptsapp.R // Import R class
    // Inside Scaffold -> topBar

    TopAppBar(title = { Text(stringResource(id = R.string.app_name)) }) // Use string resource

  5. Select Build Variant & Test:
    • In Android Studio, go to Build -> Select Build Variant… (or use the “Build Variants” panel usually docked on the left).
    • You can now choose between devDebug, devRelease, prodDebug, and prodRelease.
    • Select devDebug. Run the app. The title should say “Task Reporter (Dev)”. Data should go to tasks_dev and usage_logs_dev in Firestore.
    • Select prodDebug. Run the app. The title should be “Task Reporter”. Data should go to tasks and usage_logs.

Step 5: Proguard/R8 Configuration (for Release Builds)

R8 is the default code shrinker and obfuscator in Android Studio (successor to Proguard). It’s enabled by default for release build types. We need to ensure it doesn’t break our app, especially Firestore data mapping.

    1. Review app/build.gradle.kts Release Build Type:
      app/build.gradle.kts

      
      android {
          // ...
          buildTypes {
              release {
                  isMinifyEnabled = true // Should be true by default for release
                  isShrinkResources = true // R8 handles both
                  proguardFiles(
                      getDefaultProguardFile("proguard-android-optimize.txt"),
                      "proguard-rules.pro" // Our custom rules file
                  )
              }
              debug {
                  isMinifyEnabled = false // Usually false for debug
                  proguardFiles(
                      getDefaultProguardFile("proguard-android-optimize.txt"),
                      "proguard-rules.pro"
                  )
              }
              // ... debug build type ...
          }
          // ...
      }
                 

      isMinifyEnabled = true enables R8 for the release build type.

    2. Configure app/proguard-rules.pro:
      • Firestore uses reflection to serialize/deserialize data classes. R8 might remove or rename classes/fields needed for this process. We need to add “keep” rules.
      • Open (or create) the app/proguard-rules.pro file. Add the following:
      
      # Keep Task data class and its members for Firestore serialization
      -keep class com.yourcompany.advancedconceptsapp.data.Task { (...); *; }
      # Keep any other data classes used with Firestore similarly
      # -keep class com.yourcompany.advancedconceptsapp.data.AnotherFirestoreModel { (...); *; }
      
      # Keep Coroutine builders and intrinsics (often needed, though AGP/R8 handle some automatically)
      -keepnames class kotlinx.coroutines.intrinsics.** { *; }
      
      # Keep companion objects for Workers if needed (sometimes R8 removes them)
      -keepclassmembers class * extends androidx.work.Worker {
          public static ** Companion;
      }
      
      # Keep specific fields/methods if using reflection elsewhere
      # -keepclassmembers class com.example.SomeClass {
      #    private java.lang.String someField;
      #    public void someMethod();
      # }
      
      # Add rules for any other libraries that require them (e.g., Retrofit, Gson, etc.)
      # Consult library documentation for necessary Proguard/R8 rules.
    • Explanation:
      • -keep class ... { <init>(...); *; }: Keeps the Task class, its constructors (<init>), and all its fields/methods (*) from being removed or renamed. This is crucial for Firestore.
      • -keepnames: Prevents renaming but allows removal if unused.
      • -keepclassmembers: Keeps specific members within a class.

3. Test the Release Build:

    • Select the prodRelease build variant.
    • Go to Build -> Generate Signed Bundle / APK…. Choose APK.
    • Create a new keystore or use an existing one (follow the prompts). Remember the passwords!
    • Select prodRelease as the variant. Click Finish.
    • Android Studio will build the release APK. Find it (usually in app/prod/release/).
    • Install this APK manually on a device: adb install app-prod-release.apk.
    • Test thoroughly. Can you add tasks? Do they appear? Does the background worker still log to Firestore (check usage_logs)? If it crashes or data doesn’t save/load correctly, R8 likely removed something important. Check Logcat for errors (often ClassNotFoundException or NoSuchMethodError) and adjust your proguard-rules.pro file accordingly.

 


 

Step 6: Firebase App Distribution (for Dev Builds)

Configure Gradle to upload development builds to testers via Firebase App Distribution.

  1. Download private key: on Firebase console go to Project Overview  at left top corner -> Service accounts -> Firebase Admin SDK -> Click on “Generate new private key” button ->
    api-project-xxx-yyy.json move this file to root project at the same level of app folder *Ensure that this file be in your local app, do not push it to the remote repository because it contains sensible data and will be rejected later
  2. Configure App Distribution Plugin in app/build.gradle.kts:
    app/build.gradle.kts

    
    // Apply the plugin at the top
    plugins {
        // ... other plugins id("com.android.application"), id("kotlin-android"), etc.
        alias(libs.plugins.google.firebase.appdistribution)
    }
    
    android {
        // ... buildFeatures, flavorDimensions, productFlavors ...
    
        buildTypes {
            getByName("release") {
                isMinifyEnabled = true // Should be true by default for release
                isShrinkResources = true // R8 handles both
                proguardFiles(
                    getDefaultProguardFile("proguard-android-optimize.txt"),
                    "proguard-rules.pro" // Our custom rules file
                )
            }
            getByName("debug") {
                isMinifyEnabled = false // Usually false for debug
                proguardFiles(
                    getDefaultProguardFile("proguard-android-optimize.txt"),
                    "proguard-rules.pro"
                )
            }
            firebaseAppDistribution {
                artifactType = "APK"
                releaseNotes = "Latest build with fixes/features"
                testers = "briew@example.com, bri@example.com, cal@example.com"
                serviceCredentialsFile="$rootDir/api-project-xxx-yyy.json"//do not push this line to the remote repository or stablish as local variable } } } 

    Add library version to libs.version.toml

    
    [versions]
    googleFirebaseAppdistribution = "5.1.1"
    [plugins]
    google-firebase-appdistribution = { id = "com.google.firebase.appdistribution", version.ref = "googleFirebaseAppdistribution" }
    
    Ensure the plugin classpath is in the 

    project-level

     build.gradle.kts: 

    project build.gradle.kts

    
    plugins {
        // ...
        alias(libs.plugins.google.firebase.appdistribution) apply false
    }
                    

    Sync Gradle files.

  3. Upload a Build Manually:
    • Select the desired variant (e.g., devDebugdevRelease, prodDebug , prodRelease).
    • In Android Studio Terminal  run  each commmand to generate apk version for each environment:
      • ./gradlew assembleRelease appDistributionUploadProdRelease
      • ./gradlew assembleRelease appDistributionUploadDevRelease
      • ./gradlew assembleDebug appDistributionUploadProdDebug
      • ./gradlew assembleDebug appDistributionUploadDevDebug
    • Check Firebase Console -> App Distribution -> Select .dev project . Add testers or use the configured group (`android-testers`).

Step 7: CI/CD with GitHub Actions

Automate building and distributing the `dev` build on push to a specific branch.

  1. Create GitHub Repository. Create a new repository on GitHub and push your project code to it.
    1. Generate FIREBASE_APP_ID:
      • on Firebase App Distribution go to Project Overview -> General -> App ID for com.yourcompany.advancedconceptsapp.dev environment (1:xxxxxxxxx:android:yyyyyyyyyy)
      • In GitHub repository go to Settings -> Secrets and variables -> Actions -> New repository secret
      • Set the name: FIREBASE_APP_ID and value: paste the App ID generated
    2. Add FIREBASE_SERVICE_ACCOUNT_KEY_JSON:
      • open api-project-xxx-yyy.json located at root project and copy the content
      • In GitHub repository go to Settings -> Secrets and variables -> Actions -> New repository secret
      • Set the name: FIREBASE_SERVICE_ACCOUNT_KEY_JSON and value: paste the json content
    3. Create GitHub Actions Workflow File:
      • In your project root, create the directories .github/workflows/.
      • Inside .github/workflows/, create a new file named android_build_distribute.yml.
      • Paste the following content:
    4. 
      name: Android CI 
      
      on: 
        push: 
          branches: [ "main" ] 
        pull_request: 
          branches: [ "main" ] 
      jobs: 
        build: 
          runs-on: ubuntu-latest 
          steps: 
          - uses: actions/checkout@v3
          - name: set up JDK 17 
            uses: actions/setup-java@v3 
            with: 
              java-version: '17' 
              distribution: 'temurin' 
              cache: gradle 
          - name: Grant execute permission for gradlew 
            run: chmod +x ./gradlew 
          - name: Build devRelease APK 
            run: ./gradlew assembleRelease 
          - name: upload artifact to Firebase App Distribution
            uses: wzieba/Firebase-Distribution-Github-Action@v1
            with:
              appId: ${{ secrets.FIREBASE_APP_ID }}
              serviceCredentialsFileContent: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_KEY_JSON }}
              groups: testers
              file: app/build/outputs/apk/dev/release/app-dev-release-unsigned.apk
      
    1. Commit and Push: Commit the .github/workflows/android_build_distribute.yml file and push it to your main branch on GitHub.
    1. Verify: Go to the “Actions” tab in your GitHub repository. You should see the workflow running. If it succeeds, check Firebase App Distribution for the new build. Your testers should get notified.

 


 

Step 8: Testing and Verification Summary

    • Flavors: Switch between devDebug and prodDebug in Android Studio. Verify the app name changes and data goes to the correct Firestore collections (tasks_dev/tasks, usage_logs_dev/usage_logs).
    • WorkManager: Use the App Inspection -> Background Task Inspector or ADB commands to verify the ReportingWorker runs periodically and logs data to the correct Firestore collection based on the selected flavor.
    • R8/Proguard: Install and test the prodRelease APK manually. Ensure all features work, especially adding/viewing tasks (Firestore interaction). Check Logcat for crashes related to missing classes/methods.
    • App Distribution: Make sure testers receive invites for the devDebug (or devRelease) builds uploaded manually or via CI/CD. Ensure they can install and run the app.
    • CI/CD: Check the GitHub Actions logs for successful builds and uploads after pushing to the develop branch. Verify the build appears in Firebase App Distribution.

 

Conclusion

Congratulations! You’ve navigated complex Android topics including Firestore, WorkManager, Compose, Flavors (with correct Firebase setup), R8, App Distribution, and CI/CD.

This project provides a solid foundation. From here, you can explore:

    • More complex WorkManager chains or constraints.
    • Deeper R8/Proguard rule optimization.
    • More sophisticated CI/CD pipelines (deploy signed apks/bundles, running tests, deploying to Google Play).
    • Using different NoSQL databases or local caching with Room.
    • Advanced Compose UI patterns and state management.
    • Firebase Authentication, Cloud Functions, etc.

If you want to have access to the full code in my GitHub repository, contact me in the comments.


 

Project Folder Structure (Conceptual)


AdvancedConceptsApp/
├── .git/
├── .github/workflows/android_build_distribute.yml
├── .gradle/
├── app/
│   ├── build/
│   ├── libs/
│   ├── src/
│   │   ├── main/           # Common code, res, AndroidManifest.xml
│   │   │   └── java/com/yourcompany/advancedconceptsapp/
│   │   │       ├── data/Task.kt
│   │   │       ├── ui/TaskScreen.kt, TaskViewModel.kt, theme/
│   │   │       ├── worker/ReportingWorker.kt
│   │   │       └── MainActivity.kt
│   │   ├── dev/            # Dev flavor source set (optional overrides)
│   │   ├── prod/           # Prod flavor source set (optional overrides)
│   │   ├── test/           # Unit tests
│   │   └── androidTest/    # Instrumentation tests
│   ├── google-services.json # *** IMPORTANT: Contains configs for BOTH package names ***
│   ├── build.gradle.kts    # App-level build script
│   └── proguard-rules.pro # R8/Proguard rules
├── api-project-xxx-yyy.json # Firebase service account key json
├── gradle/wrapper/
├── build.gradle.kts      # Project-level build script
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
        

 

]]>
https://blogs.perficient.com/2025/04/10/android-development-codelab-mastering-advanced-concepts/feed/ 0 379698
We Are Perficient: Transforming the Digital Strategies with Adobe https://blogs.perficient.com/2025/03/31/we-are-perficient-transforming-the-mobile-experience-and-digital-strategies-with-adobe/ https://blogs.perficient.com/2025/03/31/we-are-perficient-transforming-the-mobile-experience-and-digital-strategies-with-adobe/#comments Mon, 31 Mar 2025 20:26:09 +0000 https://blogs.perficient.com/?p=379495

Today in our “We Are Perficient” series, we explore how businesses can take their digital experience to the next level through mobile optimization. In an exclusive conversation with Jonathan Crockett, Managing Director of Go-To-Market, Sales, and Solutions at Perficient, we dive into key strategies to ensure brands deliver seamless, high-impact experiences on mobile devices. 

In today’s digital world, user experience is everything. Companies looking to stand out must provide seamless, personalized, and optimized interactions at every touchpoint. In this video, we explore how the combination of Artificial Intelligence, advanced digital experience strategies, and collaboration with technology leaders like Adobe is redefining the way brands connect with their customers. 

Optimizing for a Mobile-First World 

 Today, most digital interactions happen on mobile devices. Without a well-optimized mobile strategy, brands risk losing conversions and engagement. From ultra-fast loading times to intuitive and accessible interfaces, mobile optimization is no longer optional—it’s essential to improving customer retention and conversion rates. 

 AI-Driven Personalization 

Artificial intelligence is transforming user experiences by enabling real-time personalization based on data. From content recommendations to adaptive interfaces that respond to user behavior, AI helps deliver unique and relevant experiences at every interaction. This not only enhances customer satisfaction but also boosts lifetime value and brand loyalty. 

Adobe and the Digital Strategies Evolution 

As an Adobe strategic partner, Perficient helps businesses unlock the full potential of Adobe’s cutting-edge solutions. From Adobe Experience Manager to Adobe Sensei, our strategies merge creativity and technology to design immersive, scalable, and highly effective digital experiences. 

Ready to Take Your Digital Strategies to the Next Level? 

The future of digital experience lies in personalization, optimization, and continuous innovation. If you’re looking to transform how your customers interact with your brand, Perficient can help. 

Contact us today and discover how we can elevate your digital strategy. 

]]>
https://blogs.perficient.com/2025/03/31/we-are-perficient-transforming-the-mobile-experience-and-digital-strategies-with-adobe/feed/ 1 379495
Kotlin Multiplatform vs. React Native vs. Flutter: Building Your First App https://blogs.perficient.com/2025/02/26/kotlin-multiplatform-vs-react-native-vs-flutter-building-your-first-app/ https://blogs.perficient.com/2025/02/26/kotlin-multiplatform-vs-react-native-vs-flutter-building-your-first-app/#respond Wed, 26 Feb 2025 21:50:16 +0000 https://blogs.perficient.com/?p=377508

Choosing the right framework for your first cross-platform app can be challenging, especially with so many great options available. To help you decide, let’s compare Kotlin Multiplatform (KMP), React Native, and Flutter by building a simple “Hello World” app with each framework. We’ll also evaluate them across key aspects like setup, UI development, code sharing, performance, community, and developer experience. By the end, you’ll have a clear understanding of which framework is best suited for your first app.

Building a “Hello World” App

1. Kotlin Multiplatform (KMP)

Kotlin Multiplatform allows you to share business logic across platforms while using native UI components. Here’s how to build a “Hello World” app:

Steps:

  1. Set Up the Project:
    • Install Android Studio and the Kotlin Multiplatform Mobile plugin.
    • Create a new KMP project using the “Mobile Library” template.
  2. Shared Code:In the shared module, create a Greeting class with a function to return “Hello World”.
    // shared/src/commonMain/kotlin/Greeting.kt
    class Greeting {
        fun greet(): String {
            return "Hello, World!"
        }
    }
  3. Platform-Specific UIs:For Android, use Jetpack Compose or XML layouts in the androidApp module. For iOS, use SwiftUI or UIKit in the iosApp module.Android (Jetpack Compose):
    // androidApp/src/main/java/com/example/androidApp/MainActivity.kt
    class MainActivity : ComponentActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContent {
                Text(text = Greeting().greet())
            }
        }
    }

    iOS (SwiftUI):

    // iosApp/iosApp/ContentView.swift
    struct ContentView: View {
        var body: some View {
            Text(Greeting().greet())
        }
    }
  4. Run the App:Build and run the app on Android and iOS simulators/emulators.

Pros and Cons:

Pros:

  • Native performance and look.
  • Shared business logic reduces code duplication.

Cons:

  • Requires knowledge of platform-specific UIs (Jetpack Compose for Android, SwiftUI/UIKit for iOS).
  • Initial setup can be complex.

2. React Native

React Native allows you to build cross-platform apps using JavaScript and React. Here’s how to build a “Hello World” app:

Steps:

  1. Set Up the Project:
    • Install Node.js and the React Native CLI.
    • Create a new project:
      npx react-native init HelloWorldApp
  2. Write the Code:Open App.js and replace the content with the following:
    import React from 'react';
    import { Text, View } from 'react-native';
    
    const App = () => {
        return (
            <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
                <Text>Hello, World!</Text>
            </View>
        );
    };
    
    export default App;
  3. Run the App:Start the Metro bundler:
    npx react-native start

    Run the app on Android or iOS:

    npx react-native run-android
    npx react-native run-ios

Pros and Cons:

Pros:

  • Easy setup and quick development.
  • Hot reload for instant updates.

Cons:

  • Performance may suffer for complex apps due to the JavaScript bridge.
  • Limited native look and feel.

3. Flutter

Flutter is a UI toolkit for building natively compiled apps for mobile, web, and desktop using Dart. Here’s how to build a “Hello World” app:

Steps:

  1. Set Up the Project:
    • Install Flutter SDK and Android Studio/VS Code.
    • Create a new project:
      flutter create hello_world_app
  2. Write the Code:Open lib/main.dart and replace the content with the following:
    import 'package:flutter/material.dart';
    
    void main() {
        runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
            return MaterialApp(
                home: Scaffold(
                    appBar: AppBar(title: Text('Hello World App')),
                    body: Center(child: Text('Hello, World!')),
                ),
            );
        }
    }
  3. Run the App:Run the app on Android or iOS:
    flutter run

Pros and Cons:

Pros:

  • Single codebase for UI and business logic.
  • Excellent performance and rich UI components.

Cons:

  • Larger app size compared to native apps.
  • Requires learning Dart.

Comparing the Frameworks

1. Initial Setup

  • KMP: Moderate setup complexity, especially for iOS. Requires configuring Gradle files and platform-specific dependencies.
  • React Native: Easy setup with tools like Expo and React Native CLI.
  • Flutter: Smoothest setup with the Flutter CLI and flutter doctor command.

Best option: Flutter (for ease of initial setup).

2. UI Development

  • KMP: Platform-specific UIs (Jetpack Compose for Android, SwiftUI/UIKit for iOS). Offers native flexibility but requires separate UI code.
  • React Native: Declarative UI with JSX. Powerful but can feel like a middle ground between native and custom rendering.
  • Flutter: Widget-based system for consistent cross-platform UIs. Highly customizable but requires learning Dart.

Best option: A tie between KMP (for native UI flexibility) and Flutter (for cross-platform consistency).

3. Code Sharing

  • KMP: Excels at sharing business logic while allowing native UIs.
  • React Native: High code sharing but may require platform-specific code for advanced features.
  • Flutter: High code sharing for both UI and business logic but requires Dart.

Best option: Kotlin Multiplatform (for its focus on sharing business logic).

4. Performance

  • KMP: Native performance due to native UIs and compiled shared code.
  • React Native: Good performance but can struggle with complex UIs due to the JavaScript bridge.
  • Flutter: Excellent performance, often close to native, but may not match native performance in all scenarios.

Winner: Kotlin Multiplatform (for native performance).

5. Community and Ecosystem

  • KMP: Growing community backed by JetBrains. Kotlin ecosystem is mature.
  • React Native: Large and active community with a rich ecosystem.
  • Flutter: Thriving community with strong Google support.

Best option: React Native (for its large and mature community), but Flutter is a close contender.

6. Developer Experience

  • KMP: Gentle learning curve for Kotlin developers but requires platform-specific UI knowledge.
  • React Native: Familiar for JavaScript/React developers but may require native mobile knowledge.
  • Flutter: Excellent developer experience with hot reload and comprehensive documentation.

Best option: Flutter (for its excellent developer experience and tooling).

7. AI-Assisted Development Speed

With the rise of AI tools like GitHub Copilot, ChatGPT, Gemini, Claude, etc.. Developers can significantly speed up app development. Let’s evaluate how each framework benefits from AI assistance:

  • KMP: AI tools can help generate Kotlin code for shared logic and even platform-specific UIs. However, the need for platform-specific knowledge may limit the speed gains.
  • React Native: JavaScript is widely supported by AI tools, making it easy to generate boilerplate code, components, and even entire screens. The large ecosystem also means AI can suggest relevant libraries and solutions.
  • Flutter: Dart is less commonly supported by AI tools compared to JavaScript, but Flutter’s widget-based system is highly structured, making it easier for AI to generate consistent and functional code.

Best option: React Native (due to JavaScript’s widespread support in AI tools).

The resolution:

There’s no one-size-fits-all answer. The best choice depends on your priorities:

    • Prioritize Performance and Native UI: Choose Kotlin Multiplatform.
    • Prioritize Speed of Development and a Large Community: Choose React Native.
    • Prioritize Ease of Use, Cross-Platform Consistency, and Fast Development: Choose Flutter.

For Your First App:

  • Simple App, Fast Development: Flutter is an excellent choice. Its ease of setup, hot reload, and comprehensive widget system will get you up and running quickly.
  • Existing Kotlin/Android Skills, Focus on Shared Logic: Kotlin Multiplatform allows you to leverage your existing knowledge while sharing a significant portion of your codebase.
  • Web Developer, Familiar with React: React Native is a natural fit, allowing you to utilize your web development skills for mobile development.

Conclusion

Each framework has its strengths and weaknesses, and the best choice depends on your team’s expertise, project requirements, and long-term goals. For your first app, consider starting with Flutter for its ease of use and fast development, React Native if you’re a web developer, or Kotlin Multiplatform if you’re focused on performance and native UIs.

Try building a simple app with each framework to see which one aligns best with your preferences and project requirements.

References

  1. Kotlin Multiplatform Documentation: https://kotlinlang.org/docs/multiplatform.html
  2. React Native Documentation: https://reactnative.dev/docs/getting-started
  3. Flutter Documentation: https://flutter.dev/docs
  4. JetBrains Blog on KMP: https://blog.jetbrains.com/kotlin/
  5. React Native Community: https://github.com/react-native-community
  6. Flutter Community: https://flutter.dev/community

 

]]>
https://blogs.perficient.com/2025/02/26/kotlin-multiplatform-vs-react-native-vs-flutter-building-your-first-app/feed/ 0 377508
Perficient Recognized as Oil and Gas Industry Provider Transforming Leading Companies https://blogs.perficient.com/2024/12/20/perficient-recognized-as-oil-and-gas-industry-provider-transforming-leading-companies/ https://blogs.perficient.com/2024/12/20/perficient-recognized-as-oil-and-gas-industry-provider-transforming-leading-companies/#respond Fri, 20 Dec 2024 15:51:52 +0000 https://blogs.perficient.com/?p=372790

In the face of electrification, evolving consumer behavior and expectations, sustainability initiatives, regulatory pressures, and geopolitical volatility, oil and gas companies are being challenged to shift their approach and innovate to stay competitive. While there’s a continued focus on the digital experience for customers especially in the downstream sector, companies are also pressured to address ESG policies and reporting from production to transport and sale of their products. The development of plans to utilize emerging technologies with data-driven approaches remains integral, however, they’re executing on these all while weaving through one merger and acquisition after another.

We are excited to announce that Perficient was recently recognized by a leading global technology research and advisory firm’s report highlighting notable oil and gas industry consultancies in the U.S. and Europe. Perficient experts have worked closely with organizations within the industry to overcome challenges and gain a competitive advantage with digital transformation.

“A key differentiator for Perficient is approaching each challenge with a deep understanding of the oil and gas industry while also tapping into innovative solutions that have secured real results in other industries.” – John Latham, GM, Houston

By keeping a pulse on the ever-changing trends and pain points within the industry, maintaining cutting-edge capabilities in technology, and conducting first-party research to inform strategy, we deliver results-driven solutions that our partners are seeking.

Data Analytics and App Development for Improved Worker Safety

Like in many industries, oil and gas companies are not immune to siloed and inaccessible data. We help these organizations access, consolidate, and manage that information easily. We’ve completed numerous projects in app development, such as shift handover applications and integrated many worker safety programs, including a system to monitor gas within trucks without the need to open lids and send personnel onto dangerous catwalks.

Streamlined Transitions Throughout Mergers and Acquisitions

Over the years, we’ve helped oil and gas companies navigate the growing number of mergers and acquisitions in the industry. When one company acquires another, they want system integration as quickly as possible. Post-merger integration, supply chain and logistics, supplier management, and standardizing systems across processes are playbooks we’ve written for not just oil and gas, but every industry we’ve worked in. Further, the abundance of data that occurs due to mergers is something we expertly handle to prevent further siloing.

Cross-Industry Solutions in Oil and Gas

Oil and gas companies are stretching beyond their role as service providers to act as retailers and manufacturers. They are beginning to delve into solutions like loyalty programs and hiring executives from Target and other big box retail environments. Gas stations are now mini supermarkets striving to increase foot traffic and the size of customer baskets.  Further, all eyes are on the automotive industry as energy companies are attempting to predict the demand for gasoline and what it would look like to provide electric vehicle charging stations.

Our work across industries has made us a trusted partner and resource for these organizations hoping to build on strategies and insights from other markets. Our inclusion in this report reflects the countless hours devoted to our partnerships and understanding the work that matters to them so that we deliver real results.

Learn more about Perficient’s energy and utilities expertise.

 

 

 

]]>
https://blogs.perficient.com/2024/12/20/perficient-recognized-as-oil-and-gas-industry-provider-transforming-leading-companies/feed/ 0 372790
Unit Testing in Android Apps: A Deep Dive into MVVM https://blogs.perficient.com/2024/11/26/unit-testing-in-android-apps-a-deep-dive-into-mvvm/ https://blogs.perficient.com/2024/11/26/unit-testing-in-android-apps-a-deep-dive-into-mvvm/#respond Tue, 26 Nov 2024 19:56:40 +0000 https://blogs.perficient.com/?p=372567

Understanding Unit Testing

Unit testing is a crucial aspect of software development, especially in complex applications like Android apps. It involves testing individual units of code, such as methods or classes, in isolation. This ensures the correctness of each component, leading to a more robust and reliable application.

Why Unit Testing in MVVM?

The Model-View-ViewModel (MVVM) architectural pattern is widely adopted in Android app development. It separates the application into three distinct layers:

  • Model: Handles data logic and interacts with data sources.
  • View: Responsible for the UI and user interactions.
  • ViewModel: Acts as a bridge between the View and Model, providing data and handling UI logic.

Unit testing each layer in an MVVM architecture offers numerous benefits:

  • Early Bug Detection: Identify and fix issues before they propagate to other parts of the app.
  • Improved Code Quality: Write cleaner, more concise, and maintainable code.
  • Accelerated Development: Refactor code and add new features with confidence.
  • Enhanced Collaboration: Maintain consistent code quality across the team.

Setting Up the Environment

  1. Android Studio: Ensure you have the latest version installed.
  2. Testing Framework: Add the necessary testing framework to your app/build.gradle file:

    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
  3. Testing Library: Consider using a testing library like Mockito or MockK to create mock objects for testing dependencies.

Unit Testing ViewModels

  1. Create a Test Class: Create a separate test class for each ViewModel you want to test.
  2. Set Up Test Dependencies: Use dependency injection frameworks like Dagger Hilt or Koin to inject dependencies into your ViewModel. For testing, use mock objects to simulate the behavior of these dependencies.
  3. Write Test Cases: Write comprehensive test cases covering various scenarios:
  • Input Validation: Test how the ViewModel handles invalid input.
  • Data Transformation: Test how the ViewModel transforms data from the Model.
  • UI Updates: Test how the ViewModel updates the UI through LiveData or StateFlow.
  • Error Handling: Test how the ViewModel handles errors and exceptions.

Example:

@RunWith(AndroidJUnit4::class)
class MyViewModelTest {

    @Test
    fun `should update the UI when data is fetched successfully`() {
        // ... (Arrange)
        val viewModel = MyViewModel(mockRepository)

        // ... (Act)
        viewModel.fetchData()

        // ... (Assert)
        viewModel.uiState.observeForever { uiState ->
            assertThat(uiState.isLoading).isFalse()
            assertThat(uiState.error).isNull()
            assertThat(uiState.data).isEqualTo(expectedData)
        }
    }
}

Unit Testing Repositories

  1. Create Test Classes: Create separate test classes for each Repository class.
  2. Set Up Test Dependencies: Use dependency injection to inject dependencies into your Repository. For testing, use mock objects to simulate the behavior of data sources like databases or network APIs.
  3. Write Test Cases: Write test cases to cover:
  • Data Fetching: Test how the Repository fetches data from remote or local sources.
  • Data Storage: Test how the Repository stores and retrieves data.
  • Data Manipulation: Test how the Repository processes and transforms data.
  • Error Handling: Test how the Repository handles errors and exceptions.

Example:

@RunWith(AndroidJUnit4::class)
class MyRepositoryTest {

    @Test
    fun `should fetch data from remote source successfully`() {
        // ... (Arrange)
        val mockApi = mock(MyApi::class.java)
        val repository = MyRepository(mockApi)

        // ... (Act)
        repository.fetchData()

        // ... (Assert)
        verify(mockApi).fetchData()
    }
}

Implementing SonarQube

SonarQube is a powerful tool for code quality and security analysis. Here’s a detailed guide on how to integrate SonarQube with your Android project:

  1. Set Up SonarQube Server:
  • Install SonarQube Server: Download and install the SonarQube server on your machine or a server.
  • Configure SonarQube: Configure the server with database settings, user authentication, and other necessary parameters.
  • Start SonarQube Server: Start the SonarQube server.
  1. Configure SonarQube Scanner:
  • Install SonarQube Scanner: Download and install the SonarQube Scanner.
  • Configure Scanner Properties: Create a sonar-scanner.properties file in your project’s root directory and configure the following properties:

    sonar.host.url=http://localhost:9000
    sonar.login=your_sonar_login
    sonar.password=your_sonar_password
    sonar.projectKey=my-android-project
    sonar.projectName=My Android Project
    sonar.sources=src/main/java
    sonar.java.binaries=build/intermediates/javac/release/classes
  1. Integrate SonarQube with Your Build Process:
  • Gradle: Add the SonarQube Gradle plugin to your build.gradle file:

    plugins {
        id 'org.sonarsource.scanner-gradle' version '3.3'
    }

    Configure the plugin with your SonarQube server URL and authentication token.

  • Maven: Add the SonarQube Maven plugin to your pom.xml file. Configure the plugin with your SonarQube server URL and authentication token.
  1. Run SonarQube Analysis:
  • Execute the SonarQube analysis using the SonarQube Scanner. This can be done manually or integrated into your CI/CD pipeline.
  1. Analyze the Results:
  • Once the analysis is complete, you can view the results on the SonarQube dashboard. The dashboard provides insights into code quality, security vulnerabilities, and potential improvements.

Implementing Test Coverage with Bitrise

Test coverage measures the percentage of your code that is covered by tests. It’s a crucial metric to assess the quality of your test suite. Here’s how to measure test coverage with Bitrise:

  1. Configure Code Coverage Tool: Add a code coverage tool like JaCoCo to your project. Configure it to generate coverage reports in a suitable format (e.g., XML).
  2. Add Code Coverage Step to Bitrise Workflow: Add a step to your Bitrise Workflow to generate the code coverage report. This step should execute your tests and generate the report.
  3. Upload Coverage Report to SonarQube: Add a step to upload the generated code coverage report to SonarQube. This will allow SonarQube to analyze the report and display the coverage metrics.

Best Practices for Unit Testing

  • Write Clear and Concise Tests: Use descriptive names for test methods and variables.
  • Test Edge Cases: Consider testing scenarios with invalid input, empty data, or network errors.
  • Use a Testing Framework: A testing framework like JUnit provides a structured way to write and run tests.
  • Leverage Mocking: Use mocking frameworks like Mockito or MockK to isolate units of code and control their behavior.
  • Automate Testing: Integrate unit tests into your CI/CD pipeline to ensure code quality.
  • Review and Refactor Tests: Regularly review and refactor your tests to keep them up-to-date and maintainable.

By following these guidelines and incorporating unit testing into your development process, you can significantly improve the quality and reliability of your Android apps.

]]>
https://blogs.perficient.com/2024/11/26/unit-testing-in-android-apps-a-deep-dive-into-mvvm/feed/ 0 372567
Set Your API Performance on Fire With BlazeMeter https://blogs.perficient.com/2024/05/20/set-your-api-performance-on-fire-with-blazemeter/ https://blogs.perficient.com/2024/05/20/set-your-api-performance-on-fire-with-blazemeter/#respond Mon, 20 May 2024 15:45:43 +0000 https://blogs.perficient.com/?p=358370

BlazeMeter, continuous testing platform,  is a perfect solution for your performance needs. BlazeMeter is an open-source tool that supports Web, Mobile and API implementations. You can perform large scale load and performance testing with the ability to tweak parameters to suit your needs.

We will learn step by step process on using BlazeMeter for API testing.

Register for BlazeMeter

Enter your information on the BlazeMeter site to register and get started

Configure Your First Scenario

The first time you login, you will be taken to default view of BlazeMeter with default workspace and project. Let us start configuring a new scenario.

Create a New Project

  1. Select Projects -> Create new project
  2. Name project
  3. Select Create Test
  4. Select Performance Test
  5. Now you are taken to configuration tab

 

Update Your Scenario

  1. The left section here has your test specifications
  2. Tap on Edit link and start updating your project name, let it be “FirstLoadTest”
  3. You can define scenario and test data in Scenario Definition section
  4. For this Demo we will configure API endPoint, tap on Enter URL/API calls (see picture below)
  5. In Scenario Definition enter “https://api.demoblaze.com/entries“. So we are load testing this endpoint with GET call
  6. Lets Name this scenario “DemoWithoutParameters”
  7. Tap on three dots next to Scenario definition and duplicate the scenario
  8. Name this as “DemoWithParameters”

Test Specifications

Create TestData

Create New Csvfile

  1. Next to Scenario Definition we have TestData section, tap on it
  2. You can choose from options available, for this demo we will go with “Create New Data Entity”
  3. Lets name it “DemoTestData” and Add it
  4. Tap on + icon next to entity created for parameterization options
  5. In this example we will select New CSV File
  6. You will be taken to a data table. Rename “variableName1” to “Parameter1” and “variableName2” to “Parameter2″(our variable names are “Parameter1” and “Parameter”)
  7. Enter values as “Value1” and “Value2” and Save
  8. Configure these parameters in Query Parameters section (See picture below)
  9. Now we have successfully completed building a scenario with two endpoints, you can configure one or more endpoints in one scenario

Scenariodefinition

Configure Your First Test Run

  1. Scroll down the scenario definition window to see Load Configuration section
  2. Enter Total Users, Duration, Ramp up Time. For now we can just test with 2 users, Duration: 1minute, RampupTime: 0
  3. Once you update these details observe the graphical representation of how your Load Test is going to be in the graph displayed in this section.
  4. We can also limit Requests Per Second(RPS) by enabling the toggle button for “Limit RPS” and select requests you need to limit per second
  5. We can also change number of users at run time, but this is available with only Enterprise Plan.
  6. Lets configure LoadDistribution now in “Load Distribution” section which is right below the “Load Configuration” section
  7. Select the location from where you need the requests to trigger.
  8. We can select multiple locations and distribute load across different locations, but again this feature is available with only enterprise plan
  9. For now, lets proceed by selecting one location

Load Configuration

Failure Criteria

  1. Failure Criteria is the best approach to immediately know your LoadTest Results
  2. Do you have your failure criteria defined? If yes, you can configure that in this section. This is optional, you can skip if you don’t have failure criteria defined.
  3. You can configure multiple failure criteria as well
  4. Enable “1-min slide window eval” for evaluating your loudest prior to execution
  5. Select “Stop Test?” checkbox if you want to stop the execution in case of failure
  6. Select “Ignore failure criteria during rampup” to ignore the failures during ramp-ups
  7. You can add one or more failure criteria and select this option uniquely for each criteria
  8. Select the option “Enable 1-min slide window eval for all” on top right of this section to enable for all provided failure criteria

Failure Criteria

Test Your Scenario

  1. Run your scenario by clicking on “RunTest”
  2. Wait for launch Test window to load completely
  3. Now click on “Launch Servers” button
  4. Click on “Abort Test” to abort your execution any time
  5. Observe your execution go through different stages (Pending, Booting, Downloading and Ready)
  6. Once it reaches Ready you can see your execution progress
  7. Once the execution is done you can view the summary with status as passed/failed

Blaze Executionstatus

Analyze Your LoadTest Results

  1. The important part of performance test is to analyze your KPIs
  2. You can see different KPIs in test results summary
  3. To understand more navigate to “Timeline Report” section, bottom left you can see “KPI Panel”,this panel contains different KPIS.These KPIs can be analyzed as required
  4. By default it provides generalized view, you can select single endpoint to analyze KPIs for one particular endpoint

Blazemeter Analyze Results

Schedule Your Load Tests

  1. BlazeMeter is continuous Integration tool, you can schedule your executions and view results when required
  2. Select your test from Tests Menu on top
  3. On to left of project description window you can find SCHEDULE section
  4. Tap on Add button next to it Schedule to see schedule window
  5. Configure the scheduler with required timings and Save the scheduler
  6. The new scheduler will be added to your project
  7. Delete it by tapping on Delete icon
  8. You can add multiple schedulers
  9. Toggle on/off to activate/deactivate the schedulers

Schedule Section

BlazeMeter Pros/Cons

ProsCons
Open sourceRequires a license for additional features and support
Provides Scriptless performance testingTest results analysis requires expertise
Integration with Selenium, JMeter, Gatling, LocustNeed to integrate with Selenium/JMeter to test functional scenarios
User-friendly UI
Report Monitoring from any geographic location
Integrates with CI/CD pipelines

If you are looking for a tool that services your performance needs, BlazeMeter is your best option. You can generate scripts with its scriptless UI, simulate loads and run your tests. You can also simulate the spinning up servers, script runs and results generated within seconds.

For more information about Perficient’s Mobile Solutions expertise, subscribe to our blog or contact our Mobile Solutions team today!

]]>
https://blogs.perficient.com/2024/05/20/set-your-api-performance-on-fire-with-blazemeter/feed/ 0 358370
Flutter – Trend Setter in Mobile App Development https://blogs.perficient.com/2022/08/10/flutter-trend-setter-in-mobile-app-development/ https://blogs.perficient.com/2022/08/10/flutter-trend-setter-in-mobile-app-development/#comments Wed, 10 Aug 2022 07:42:06 +0000 https://blogs.perficient.com/?p=312423

In today’s contemporary world, mobile app development is evolving and progressing, giving mobile apps a gradual but steady makeover. All mobile applications are not developed the same way. There are many different ways of developing mobile applications in today’s market like native platforms, web, progressive web apps (PWAs), cross-platform app development, etc. 

When creating native applications, developers are guided by specific OS requirements. A native app can fully use the available features and capabilities installed on a targeted computing device. The drawback is that a native app is not compatible with other platforms. To reach wider audiences, you would need to develop several solutions (one app for each targeted platform), which is time-consuming and cost-intensive.

Cross-platform app development allows you to create new solutions that consume less development time, run on multiple platforms and reach larger audiences in a cost-effective manner. It is evolving, becoming more dynamic and attractive for developers.

Now the question is how to find a reliable platform with all these perks for building an app. Although there are numerous frameworks, present out there. Each framework has its advantages and disadvantages.

Some of the most difficult challenges that cross-platform developers faced were as follows:

  • Time Constraint
  • Steep development cost
  • More number of employees
  • No cross-platform dependency

What is Flutter?

But fortunately, Flutter changed the game by stepping into the field of app development and setting new trends in mobile application development.

Google unveiled Flutter in 2007 as a solution to all of the ongoing issues in the mobile application development industry. It is a strong language that comes with a solid mobile framework. Flutter transforms the app development process. Google’s user interface tool kit provides a simple, efficient, powerful, and easy-to-understand SDK for developing mobile applications in Dart, Google’s own programming language. One can build, test and deploy beautiful mobile, web, desktop, and embedded apps from a single codebase.

Apart from the obvious benefit of being able to create cross-platform apps, Flutter also includes its own material design and graphics library. This allows for faster app development while still producing stunning visuals regardless of the platform.

What Sets Flutter Apart as a Trendsetter?

Let us see the features that make Flutter a real trendsetter in mobile application development.

Single codebase

Flutter’s unique codebase feature makes it easy to develop mobile apps. A single codebase eliminates the conventional restrictions where developers had to write different codes depending on the platform. This now makes the process easier. Now Flutter developers need to develop code only once on Android and iPhone. Flutter’s cross-platform development framework makes it easier for developers and users to design, speed up, and improve the overall quality of an application.

Easy development language

The Flutter application development process is very efficient. Since only one code is required, it eases and accelerates the process, making it simpler and more efficient. The single codebase approach allows developers to reuse it with different plugins, thus cutting the development time short. Also, when it comes to testing, a simple quality assurance process is enough to verify a cross-platform mobile app’s functionality, features, and program.

Easy setup and maintenance

The Flutter application is relatively simple to develop and maintain due to a single codebase. It improves application performance compared to other app development platforms and reduces maintenance efforts. Due to the simple and single codebase used in programming, maintenance is simple. Whenever team members notice an issue, changes are made quickly without the hassle of going back and forth on the codes. As a result, it is less expensive because you do not need to spend extra money on powerful machines. That being said, with the team’s assistance, anyone can easily begin developing a flutter app.

Utilisation of widgets

Flutter developers know the fact that widgets are a very important part of the application interface. Flutter integrated apps provide a wide range of widgets, including navigation, scrolling, fonts, and customizable themes, regardless of the screen size. There is no denying the fact that Flutter mobile apps provide a very smooth UI experience compared to other cross-platform framework.

Best suited for MVP

The speed with which you can create your MVP (Minimum Viable Product) for any app on Flutter is unparalleled. To create an MVP in Flutter, you only need to invest a small amount of time and effort. Because nearly all codes are swapped between iOS and Android apps, the Flutter SDK has less coding. As a result, the cost of Flutter app development services for a startup, especially for MVPs, is significantly reduced.

Hot reloading

Flutter cross-platform application development is trending due to features like “Hot Reloading” or “Hot Restart.” These features allow developers to view changes in the code within one second. In simple words, as the developers are coding, they can see the progress side by side. This, in turn, increases the productivity of the developers. Also, this feature is extraordinary for bug fixing.

Efficient code writing and app testing

The Flutter application development process is very efficient. Since only one code is required, it eases and accelerates the process, making it simpler and more efficient. The single codebase approach allows developers to reuse it with different plugins, thus cutting the development time short. Also, when it comes to testing, a simple quality assurance process is enough to verify a cross-platform mobile app’s functionality, features, and program.

Modification and customization are super easy 

Flutter manages every aspect of app development, from development and maintenance to testing and customization. Flutter-powered apps are simple to modify because of the single codebase. The app’s long-term performance is maintained by easy maintenance. Any problem in the codebase can easily be fixed in minutes. Developers can eliminate the hassle of writing code by using a single codebase. So, entrepreneurs don’t need to spend more on Flutter app maintenance and customization than they do on other platforms.

Massive Support From Google

As we all know that Flutter is developed and maintained by Google. Google supports Flutter developers by providing frequent updates and problem fixes. There are many ready-made SDKs available for many Google products like Firebase.

Get Started With Flutter

Google’s Flutter is a real revolutionary in the world of mobile application development!

It has enormous potential for companies that work on various platforms and has a quick turnaround and go-to-market aspect. Besides that, it will save you money, resources, and a significant amount of time. Flutter is an excellent choice for any small or large company.

Flutter’s free and low-cost features contribute to its status as an easy-to-use and dependable app development platform. Companies with limited resources can expect to grow significantly with Flutter app development services to meet the needs of the future market. In this digital age, you can also choose to work with experts from outside your area.

]]>
https://blogs.perficient.com/2022/08/10/flutter-trend-setter-in-mobile-app-development/feed/ 1 312423
How Mobile Performance and Quality can Impact your Brand Experience https://blogs.perficient.com/2022/02/25/how-mobile-performance-and-quality-can-impact-your-brand-experience/ https://blogs.perficient.com/2022/02/25/how-mobile-performance-and-quality-can-impact-your-brand-experience/#respond Fri, 25 Feb 2022 16:16:53 +0000 https://blogs.perficient.com/?p=305377

For companies building and managing consumer-facing mobile apps, understanding the connection between brand experiences, your mobile app experience, and your ability to build positive brand equity is crucial.

Your Brand Experience

Your app is your brand. When users download and install your mobile app, they’re establishing a straight line between the experience they have in your app and your total brand experience. Your brand sets user expectations and from the very first touchpoint, they’re not just “using a mobile app”, they’re having a one-on-one interaction with your company, product, and ultimately, your overall brand. Imagine your mobile app as a sales associate. Everything about them from their appearance, their demeanor, and their ability to quickly help you reflect on your brand. A user’s takeaway from that experience will drive their connection in either a positive direction, or unfortunately, a negative one.

Almost 90% of mobile app users are likely to recommend a brand after a positive mobile experience. Conversely, when your customers have a negative experience with your mobile app, they are over 60% less likely to make future purchases. App performance, including mobile app crashes, drives approximately 70% of app uninstalls.

Mobile app users are most likely to report issues related to the following:

  • User interface – Does your user interface facilitate actions and activities, or does it get in the way, creating friction? A smooth, effortless experience is the minimum that users expect. Are interface elements easy to use and are you taking advantage of data and personalization to assist in tedious tasks? Consistently testing options via multivariate testing is one way to create a habit of validating UI, ensuring that you’re providing your users with the best interface options for solving a task.
  • App performance – Nobody likes to wait. Speed and performance are crucial for app success and generating positive reviews. Being able to measure and track app performance analytics to identify areas for experience improvement is key to staying on top of application performance.
  • Functionality – Is your app doing the job your customer hired it to do? If it’s not, your users will “fire” that app quickly and move on. There are too many options for users to settle on an app that provides little to no value. Understanding the job-to-be-done is paramount to gaining the insight required to provide the right value your users are seeking.
  • Device compatibility – There are an almost infinite number of devices out there across Android and iOS. Understanding the best ways to provide a consistent experience among the broad spectrum of form factors is key to growing users, reducing frustration, and cultivating a base of enthusiastic customers. When you consider the issues that users face, along with the growing number of different scenarios across operating systems, OS versions, carrier networks, and the huge number of devices in the marketplace, you can see how important it is to make sure you have a robust quality management strategy to address the almost infinitely broad mobile ecosystem.

Building a Robust Quality Strategy

A comprehensive, proactive strategy for quality assurance is vital to making sure your users are having the most frictionless, performant experience in your mobile apps. The entire mobile ecosystem is one of the most dynamic and rapidly evolving experience platforms. Brands that stay on top of quality and performance deliver successful experiences with their mobile products, while those who merely react to negative feedback have the potential to cause irreparable damage.

Identify and Understand Issues Early

The most important part of developing a mobile quality strategy is to have a solid understanding of any potential problems. Deploying analytics and monitoring solutions are one of the first steps you should take to gain insight into what’s happening with your app and when it’s happening. These solutions provide valuable real-time feedback on the state of your mobile app experience and can help you identify potential issues. Armed with this information, you can develop a better understanding of any issues that your users are encountering and plan accordingly. You need to leverage proactive monitoring and analysis to identify friction points early. Don’t wait for users to tell you what’s wrong, by that time it’s too late.

Test and Automate

Another aspect of a robust quality strategy is to ensure that you’re testing as often as you can. You should be leveraging quality testing tools and platforms and including automation where possible. This will enable development teams to guarantee that deployed code is performing across operating systems and versions, networks, and handsets prior to getting it into users’ hands. This can be implemented as part of your deployment process and provide you valuable feedback on the quality of code being written by app engineering teams.

Why Perficient Mobile Solutions?

At Perficient, we take a holistic, product-centric approach to mobile, ensuring overall quality throughout the app lifecycle. This is key to ensuring a high-quality experience across the entire mobile landscape.

For more information about Perficient’s Mobile Solutions expertise, subscribe to our blog or contact our Mobile Solutions team today!

 

 

 

]]>
https://blogs.perficient.com/2022/02/25/how-mobile-performance-and-quality-can-impact-your-brand-experience/feed/ 0 305377
Is GraphQL Right for Your Application Architecture? https://blogs.perficient.com/2022/01/10/is-graphql-right-for-your-application-architecture/ https://blogs.perficient.com/2022/01/10/is-graphql-right-for-your-application-architecture/#respond Mon, 10 Jan 2022 15:49:04 +0000 https://blogs.perficient.com/?p=303070

Your mobile applications and web applications need to get their data from somewhere, and that somewhere is most often your API layer.  So how you design and build your APIs will have a big impact on the success of your mobile and web applications and therefore on the happiness of your customers.

One key decision in the design of your API layer is whether to choose REST or GraphQL.  Like all architectural decisions, there is no one-size fits all; you have to weigh your specific business, product, and technical goals against the merits of these two popular alternatives.  Whereas REST emphasizes creating unique endpoints for different resources, GraphQL provides an expressive query language for accessing interrelated resources via a single endpoint.  There are a lot of great posts on the internet that attempt to comprehensively compare and contrast REST versus GraphQL, and I recommend that you read them all! 🙂  This post has a more modest goal — we will discuss a few criteria to consider that can help you determine whether GraphQL might be a good fit for you and your application architecture.

It is probably safe to say that REST is the default way to build APIs in our modern era.  The RESTful pattern provides a suite of best practices that help API designers build useful, legible APIs in a fairly standard way.  There are a lot of great REST APIs out there powering the internet.  That said, GraphQL has been around for a decade now, so while it still may not be as widely adopted as REST, it is certainly no longer the new kid on the block.

One important characteristic of GraphQL is that it is designed with a schema and type system in mind.  This has important implications for how your application interacts with your API.  This schema-first approach and GraphQL’s expressive query language put more control in the hands of the client application developers.  That can make a big difference in the efficiency of the overall development process as well as the performance and quality of the final product.

Here are a few questions to ask yourself when evaluating whether GraphQL might be a good solution for your application architecture:

Are you building a brand new product or a proof of concept? Are you going to change your mind a lot?  Are your requirements rapidly evolving?  Will the presentation of the data will be continuously evolved and iterated upon?

If so, GraphQL’s schema-first approach can be very appealing.  You can design your GraphQL API to express the data and relationships without having to predict upfront exactly how user-facing applications will consume your data.  The application developers can then choose what data they need when they need it.  This allows for ease in adding and subtracting application features without having to refactor and redeploy your APIs constantly throughout the product development process.  This can really accelerate your product development process and thereby your speed to market.

Are you building a high-performance mobile app that will be sensitive to bandwidth restrictions and slow connections?

If so, it will be important to optimize what data you retrieve and how you retrieve it.  GraphQL offers the client application developer a lot of flexibility when specifying what data needs to be retrieved in a single call.  That can mean traversing an object tree from reference to reference in a single call instead of the multiple calls that might be required using REST APIs.  And that also means only getting the bits of data that you absolutely need for your app to work.  No extra cruft in the response.

Does the same data need to be presented in a variety of different ways throughout the application?

GraphQL provides a client application with an easy way to specify which particular bits of data to retrieve.  Likewise, there are good client libraries for caching data so that cached data from one call can potentially fulfill future overlapping data requests.

Are you planning to use a strongly-typed language in your mobile or web application?

If so, that should naturally play well with GraphQL’s emphasis on schema and type definitions. You will likely reap valuable developer efficiency benefits building and maintaining your app.

Are you trafficking in a lot of user-specific data? Is edge-caching (e.g. with a CDN) a lot of unauthenticated content a low priority for your application?

If so, GraphQL might be a good fit.  While edge-caching of content is certainly possible with GraphQL, implementing it is slightly more complicated than it would be with REST APIs.  This is due to GraphQL’s heavy reliance on the HTTP Post method and on the HTTP 200 response.  If edge-caching is not a priority, then you can take advantage of GraphQL’s many merits with little trade-off.  If edge-caching is a priority for your application, you can still explore using GraphQL, but just make sure that you address and solve for your caching needs upfront.

 

This is by no means an exhaustive list of considerations.  But if you answered ‘yes’ to a few of these questions, you might want to further explore using GraphQL for your application architecture.  GraphQL might be right for you.

]]>
https://blogs.perficient.com/2022/01/10/is-graphql-right-for-your-application-architecture/feed/ 0 303070
The Great Mobile Ecosystem Awakening: Looking Back on 2021’s Top Mobile Trends https://blogs.perficient.com/2021/12/21/the-great-mobile-ecosystem-awakening-looking-back-on-2021s-top-mobile-trends/ https://blogs.perficient.com/2021/12/21/the-great-mobile-ecosystem-awakening-looking-back-on-2021s-top-mobile-trends/#respond Tue, 21 Dec 2021 22:18:05 +0000 https://blogs.perficient.com/?p=302585

Mobile Apps are entering a stage of maturity to the point of ubiquity. A comprehensive approach is needed to meet the rapid shifts in consumer behaviors and the underlying technology that drives these experiences. As the mobile ecosystem matures and new capabilities emerge, user expectations have never been higher.

Let’s recap the past year in the mobile landscape and look to the future as the mobile ecosystem evolves outside of the app and into the virtual world.

2021 mobile trends

 

Narrow your Focus to What you Do Best

In 2010, there were only 210,000 apps in the Apple App Store. Today, that number has grown exponentially to 4.5M apps. Even though there are more options than ever, the average smartphone user only has about 40 apps installed on their device. In the increasingly competitive mobile landscape, a bad user experience can take you out of the game. 71% percent of app uninstalls occur due to application crashes. For any mobile product to succeed and keep users engaged, you must listen to your users. Managing a mobile product involves researching new ideas, iterating quickly, and using those learnings to move in the right direction. A mobile product runs its course until it no longer meets the needs of your business.

Keeping your users focused and engaged becomes more difficult as your app becomes more complex. Most companies are moving away from the super app concept in favor of a more focused approach. A super app is a mobile app that provides multiple services and effectively becomes an all-encompassing solution. While the emerging super app concept is the ambition of companies like Facebook and PayPal, the do-it-all approach is not always better for the end user. In most cases, apps with too many disconnected features and functionalities lack the focus and usefulness consumers expect from a mobile app.

For example, Airbnb had planned to move in the direction of creating a super app for all booking experiences. When the pandemic hit, their CEO reduced investment activities that did not support its core business of home share and experiences. The result was increased bookings for the quarter and the year. One of their competitors, Booking Holdings, took the super app approach and saw bookings fall more than Airbnb during the pandemic. Only 50% of their bookings were direct, versus 90% for Airbnb.

It pays to focus on your core offering by utilizing mobile apps to do a few things well and leave out the rest. Simplify your approach to serve up relevant content outside of your app and focus on solving customer problems. This will give your app an advantage against emerging super apps in the future.

The Experience Outside of your App is Equally Important

Android may hold the crown for worldwide market share, but Apple continually accelerates user adoption of new hardware and features. Apple’s WWDC announcements this year emphasized the importance of performance across the operating system outside of your app. Sharing, widgets, notifications, and other features have advanced and are becoming essential. It is predicted that 135.6 million US users will be using voice assistants in the coming year. Does your app work with Siri and my AirPods? How about CarPlay?

As we saw with the Apple Watch, or widgets previously, one of the toughest challenges is that these experiences provide limited real estate as you move outside of your app (smaller screens, less content, etc.). To take advantage of these experiences, you must simplify your offering and solve a few problems well. You do not have to jump on all the latest software or hardware, and some may not fit your business or solve a customer problem. Still, it is essential to monitor how it changes user behavior and listen to your users to meet their expectations. Considering the entire mobile ecosystem is critical to long term success, as the future of mobile applications is no longer limited to the phone.

Mobile Experiences Enter the Metaverse 

Apple’s top trend for apps in 2021 was connection, or apps that restore our sense of togetherness. Mark Zuckerberg recently sat down with Gary Vee and discussed a new reality commonly known as the Metaverse or Omniverse. Zuckerberg says these new experiences need to satisfy human connection and make people feel like they are together. Forward-thinking brands are already turning their attention to this new reality. Chipotle, Verizon, and Nike have built digital worlds on metaverse-like platforms such as Roblox. Web 3.0 and a decentralized system on the blockchain will require a complete overhaul of the mobile ecosystem. Digital currency/tokens and NFTs will be how users purchase and obtain digital ownership of your products.

Shipments of augmented reality and virtual reality headsets nearly tripled year-over-year at the start of 2021. Facebook recently changed its name to Meta and put $10B towards this bet in the future. Rumors are flying that Apple has a headset of their own on the horizon. A simple pilot or prototype is a great way to try out these new mediums and see how your customer responds. Sooner than later, one of these new platforms or devices will become more important than the phone itself and require you to reimagine your mobile offerings.

We’re Here to Help

Perficient’s Mobile Solutions Group specializes in Mobile Product and App Development. We partner with mobile product management and engineering teams to build and evolve your most important mobile product initiatives.

Evaluate your current mobile experience, operations, and technology with Mobile IQ℠. For more information, contact Perficient’s Mobile Solutions experts today!

 

 

 

]]>
https://blogs.perficient.com/2021/12/21/the-great-mobile-ecosystem-awakening-looking-back-on-2021s-top-mobile-trends/feed/ 0 302585
Perficient Mobile Solutions Colleagues Quoted in Forrester Report https://blogs.perficient.com/2021/11/19/perficient-mobile-solutions-colleagues-quoted-in-forrester-report/ https://blogs.perficient.com/2021/11/19/perficient-mobile-solutions-colleagues-quoted-in-forrester-report/#respond Fri, 19 Nov 2021 17:25:07 +0000 https://blogs.perficient.com/?p=300642

Creating a seamless, intuitive digital experience across all devices is vital to attracting and retaining users in the increasingly competitive modern application landscape. In All In This Together: Make The Right Call When Deciding To Integrate Mobile And Web Development, Forrester examines “what’s possible today on the mobile web — and what isn’t.”

According to the Forrester report, 57% of enterprise mobility decision-makers have adopted progressive web application (PWA) technology, while 19% indicated that they have plans for future adoption. Stephen Griffin, Managing Director of Perficient’s Mobile Solutions practice, and Quincy Mitchell, Senior Solutions Architect, were quoted in the Forrester report.

Leveraging PWAs to Increase Mobile Conversions

The user journey is not linear. Users can be acquired through a variety of channels and increasing their level of engagement is a gradual process. PWAs provide an app-like experience through common web browsers and can be leveraged to build trust with new users, ultimately increasing conversions.

Forrester states that, “If you’re hosting a PWA, users will become used to the UI. If they visit frequently enough, it makes sense to provide an install link — for either the PWA itself or a feature-rich native app.” “Making the mobile app is the easy part,” said Stephen Griffin as quoted in the report. “Getting the users and keeping the users is the hard part. PWAs are… a good funnel; you can promote a user to the native mobile app”.

Enhancing the User Experience Across Devices with PWAs

According to the Forrester report, web apps “…[are] not able to replace all fully-fledged standalone applications.” Both mobile web and native applications are necessary to provide users with enhanced experiences across different devices.

“Because of COVID, our attention has been brought to screens; the desktop is more important than ever,” said Quincy Mitchell as quoted in the Forrester report.  “Multitasking on the desktop has been more of a priority, especially for consumer experiences. It’s a no-brainer to build the web app.”

Perficient’s Expertise in Mobile Solutions

Forrester interviewed leaders from Perficient’s Mobile Solutions team while researching this report. Perficient is excited to continue to share thought leadership and perspective on emerging trends in mobile application development. For more information, download All In This Together: Make The Right Call When Deciding To Integrate Mobile And Web Development (available for purchase or to Forrester subscribers) or contact our Mobile Solutions experts today.

]]>
https://blogs.perficient.com/2021/11/19/perficient-mobile-solutions-colleagues-quoted-in-forrester-report/feed/ 0 300642
Bright Paths Students Bring Ingenuity to Custom App Development https://blogs.perficient.com/2021/05/27/bright-paths-students-bring-ingenuity-to-custom-app-development/ https://blogs.perficient.com/2021/05/27/bright-paths-students-bring-ingenuity-to-custom-app-development/#respond Thu, 27 May 2021 22:43:41 +0000 https://blogs.perficient.com/?p=292819

Perficient is a company full of unique populations, and we’re committed to investing in resources that develop the skills of our colleagues while embracing diverse perspectives and voices. It’s a commitment that Perficient made to nearly 5,000 colleagues earlier this year through the Perficient People Promise, which promises to champion, challenge, and celebrates every colleague.

Bonus: Unveiling the New Perficient People Promise with Andrea Lampert, VP of People

We also believe that diversity and inclusion are constant pursuits and that more can be done to create equitable opportunities throughout the technology industry. That’s the purpose of our Bright Path’s Program, which aims to advance STEM education and career opportunities within our communities. Over the past several weeks, our first cohort of Bright Paths students, consisting of 22 women based in Detroit, have been hard at work learning about fundamental concepts of software engineering. Recently, the students put their knowledge to work by engineering their own innovative applications and showcasing their work during a Demo Day.

Learn more about the Perficient Bright Paths Program

Perficient Proudly Presents Bright Paths Student Demos

With so many amazing examples of ingenuity, we are breaking our Bright Paths student profiles into two blog posts. Review the other Bright Paths student profiles and demos in our previous blog post. To view all the presentations in full, please enjoy the full playlist.

Melissa RiceMelissa Rice’s Bright Paths Project: WanderList

Melissa is a Michigan State University alum with a B.S. in Kinesiology who moved to Seattle, WA, soon after graduation. There, she worked at a small start-up where she was introduced to new platforms, including Salesforce. She moved back to Michigan in 2018 and started a marketing company in 2019 where she fixed and built websites using WordPress. She then decided to enroll in a front-end web development bootcamp at Grand Circus in Detroit in January 2020 where she expanded her knowledge on several software programs. Almost a year later, she saw a post about the Bright Paths cohort with Perficient and never looked back. In her free time, Melissa loves to be outdoors rock climbing, mountain biking, hiking, and kayaking.

Bright Paths Project: WanderList

WanderList is an application for people who love to travel around the U.S. to see all the beauty within it. Want to visit Zion National Park? Add it to your favorites page. Already been to Pictured Rocks National Park? Just change your Visited status from false to true!

Technology Stack: Python, Postgres, Flask, JavaScript, SQLAlchemy, JQuery, AJAX, web API | APIs Used: NPS API: https://www.nps.gov/subjects/developer/api-documentation.htm#/

More About Melissa Rice’s Bright Paths Project: WanderList

 

Nicole DreonNicole Dreon’s Bright Paths Project: Mindful Everyday – ME

After losing her Program Director job in Summer 2020 due to the COVID-19 pandemic, Nicole saw the situation as an opportunity to develop her interest in coding into a career. She enrolled in a front-end bootcamp through Grand Circus where she was awarded a full scholarship from the National Center for Women & Information Technology (NCWIT). Post-graduation, a personal friend who works at Perficient informed Nicole about the Bright Paths program. Between the bootcamp, Udacity, and self study, Nicole came to Hackbright with prior knowledge of numerous software programs. She built a website for her yoga business and is currently building a portfolio site. Nicole volunteers at Mulick Park Elementary School where she shares her love of coding with the next generation.

Bright Paths Project: Mindful Everyday – ME

Mindful Everyday is a daily journaling application that allows users to chart the quantifiable data from entries to view correlations over time. Users make morning and evening entries each day which include quality of sleep, hours slept, number of times hitting snooze, activity level, and overall quality of day. The analytics page displays each of the aforementioned items on a line chart allowing users to view possible correlations between habits. Users can view past entries on their homepage and a daily inspirational quote.

Technology Stack: Python, JavaScript, HTML, CSS, Bootstrap, Flask, Jinja, PostgreSQL, SQLAlchemy, Chart.js | APIs Used: Zen Quotes

More About Nicole Dreon’s Bright Paths Project: Mindful Everyday – ME

 

Noelle NotermannNoelle Notermann’s Bright Paths Project: GOH! (Get Out of the House)

After four years of a rigorous science and technology program, Noelle pivoted to pursue her passions for music, languages, and mathematics in college, completing two majors, a minor, a full year abroad, and earning the highest honors – all by the age of 20. She went on to earn graduate degrees in music performance and pedagogy, with focus areas in higher education administration and women in leadership. She volunteers as a conflict coach and facilitative mediator in the areas of social justice, DEI, and restorative community dialogues. A natural problem solver, Noelle began to see patterns in her vocations and avocations that could benefit from improved technologies, and thus started a journey of self-study that led to a love of coding. Prior to joining the inaugural Perficient Bright Paths program, Noelle completed Hacbright’s Target Prep Course along with self-study in Python, Agile, and software development.

Bright Paths Project: GOH! (Get Out of the House)

Based on lessons learned during the global pandemic, “GOH!” (Get Out of the House) is designed to support users in getting outside to spend more time in nearby nature, parks, and recreation locations. GOH! allows users to create a profile with preferences, and then uses the robustness of the Google Maps API to return localized parks and recreation locations that may fit their needs and interests. Return results include a user’s personalized map with markers, location information, user rating, and a link to external details about the location. After completing a profile, users are able to safely and securely login/out and save locations to their favorites with immediate updates to their personalized favorites page.

Technology Stack: Python, Flask, JavaScript, jQuery, AJAX, JSON, PostgreSQL, SQLAlchemy, Jinja, HTML, CSS,
Bootstrap, Python unittest | APIs Used: Google Maps API, Google Places API, Google Geocoding

More About Noelle Notermann’s Bright Paths Project: GOH! (Get Out of the House) | Go to GOH! (Get Out of the House)

Quanisha WilliamsQuanisha Williams’ Bright Paths Project: Family Ties

Quanisha has been interested in tech most of her life. In 2011, she received her B.A. in Computer Science and was fortunate to work her first IT job as a tech support specialist approximately six years ago. Prior to Hackbright, Quanisha had been a stay-at-home mom due to the COVID-19 pandemic. Although she loves taking care and spending time with her family, she was looking to get back into IT right away. Just recently in 2020, she became A+ and Google IT-certified. She is looking to add more certifications underneath her belt as she continues to expand her knowledge and become well-rounded in IT. While searching for a job, she stumbled across an ad for an IT training opportunity. She applied and was accepted into the program. She was later connected to Hackbright Academy with another great opportunity through Perficient Bright Paths to continue developing her knowledge.

Bright Paths Project: Family Ties

Family Ties is a web app that allows users to keep track of family events. Once a user has successfully registered and signed into their accounts, they are able to view their profile which is generated from the registration process, and can upload a profile picture through a Cloudinary API implementation. The user can also keep track of upcoming events by viewing the calendar which is implemented by the FullCalendar API. Each family has at least one admin who has the same privileges as a regular user but can also create events to be stored on the calendar.

Technology Stack: Python3, Flask, Jinja2, PostgreSQL, SQLAlchemy ORM, Javascript, JQuery, HTML, CSS, Bootstrap | APIs Used: Cloudinary, FullCalendar

More About Quanisha Williams’ Bright Paths Project: Family Ties

 

Queentesa FuggettQueenTesa Fugget’s Bright Paths Project: Rejuvenate

QueenTesa is eager to transition her career into the technology industry. With a background in education as a STEAM teacher, experience as a technology specialist, and customer service roles, she is passionate about teaching others, problem-solving, and communication. The Hackbright program is the second bootcamp she has participated in, with the first taking place through The Flatiron School. She received scholarships for both of these bootcamp programs. With this experience, QueenTesa has developed her knowledge on several software platforms and frameworks. She previously developed a job applications system, an exercise logger, and a tracker for user-created homemade hair products.

Bright Paths Project: Rejuvenate

Rejuvenate is a web application that allows a user to create recipes and add and look up food ingredients through an API.

Technology Stack: PostgreSQL, Python, Flask, Jinja, Javascript, Ajax, JQuery | APIs Used: https://developer.edamam.com/food-database-api-docs

More About QueenTesa Fugget’s Bright Paths Project: Rejuvenate

 

Rosemond HoRosemond Ho’s Bright Paths Project: Aspiration Recycling

Rosemond comes from a background in mechanical engineering where she worked in the semiconductor and consumer electronics industry. She is passionate about saving the environment and education equity and has volunteered her time and talents with the Society of Women Engineers to promote STEM with girls in K-12 education. In her spare time, she likes to read and hike, as well as watch and perform in the theater.

Bright Paths Project: Aspiration Recycling

“Aspirational Recycling” is a term that refers to people putting materials into the recycling bin that are not actually recyclable in the hopes that the items could possibly be recycled. However, non-recyclable items are bad for the recycler because they gunk up the machine and slow down the recycling process. Aspiration Recycling is a Yelp for Recyclers: users can search a database of all recyclers in the U.S. based on location and materials. Users can also provide reviews/comments on different recyclers and maintain a list of their own favorite recyclers.

Technology Stack: Python, Flask, HTML, Jinja2 | APIs Used: Earth911 API

More About Rosemond Ho’s Bright Paths Project: Aspiration Recycling

 

Sameea FatimaSameea Fatima’s Bright Paths Project: BookWorld

Sameea earned a bachelor’s degree in software engineering and has professional experience as a software consultant and software developer. With a love for coding and a passion for data science and data visualization, Sameea looks forward to developing her talents and is interested in learning new technologies to drive her career forward.

Bright Paths Project: BookWorld

BookWorld is a web application where users can search for books, add them to their personal collection, and share with their friends.

Technology Stack: Python, HTML, CSS, Jquery, Ajax, Bootstrap, SqlAlchemy, Flask, Jinja, Cloundinary | APIs Used: Google Books API, Cloudinary API

More About Sameea Fatima’s Bright Paths Project: BookWorld

 

Sarah BartonSarah Barton’s Bright Paths Project: Spelling Bee Solver

Throughout her career, Sarah has reengineered manual processes into automated and scaled solutions. During her time in finance, this took the form of automating quarterly reporting using VBA and macros. At Amazon, Sarah paired VBA with SQL to build a tool that automated a seven-step manual workflow. Most recently at Dropbox, Sarah taught herself SQL, earning the reputation as the go-to person for all things customer data. She also led her team to build an automatic PowerPoint deck generator using Python that saved the sales organization ~500 hours per quarter. Until recently, Sarah thought that these interests in scale and efficiency meant a career in operations. At Dropbox, however, she worked closely with developers on internal tooling and learned a better word for the type of work she loves: software engineering. With a newly-found interest, Sarah successfully pursued a certificate of completion from Codeacademy’s Learn Python 3 course, is currently attending Hackbright Academy and is eager to pursue a full-time career in software engineering.

Bright Paths Project: Spelling Bee Solver

Spelling Bee Solver is a full-stack web app that displays the solutions to a daily NYTimes game called Spelling Bee. Solver looks simple but packs a lot of punch in the back-end. The app asks users to input the letters for the day’s game, then hit submit. What they get in return is a list of all the words for the day’s game, and some extra queues about certain attributes. Behind the scenes, an AJAX event listener passes the form data to the server, where a Regex and three CRUD operators are fired off to create rows in the Solver database. SQLAlchemy then retrieves the relational data, and the server feeds that data back to AJAX, where it’s added to the HTML and displayed to the user. All with just one click!

Technology Stack: Python, Flask, SQLAlchemy, JavaScript, AJAX, HTML, Jinja, CSS, Bootstrap

More About Sarah Barton’s Bright Paths Project: Spelling Bee Solver | Go to Spelling Bee Solver

 

Sherry MatlockSherry Matlock’s Bright Paths Project: Mighty Missions

Sherry has hands-on expertise in quality assurance engineering and management where she has been challenged to deploy strong analytical problem-solving and project/program management to deliver quality results. During these experiences, she used her self-taught skills with HTML and Javascript to create an intranet work site for work processes and documents. Sherry is eager to further develop her software engineering knowledge through the Perficient Bright Paths Program with Hackbright Academy.

Bright Paths Project: Might Missions

Mighty Missions Network is a database and networking site for mission-driven organizations such as nonprofits and social enterprises. Its purpose is to facilitate networking and collaboration among small organizations with a similar mission or cause. Through successful collaboration and networking, these organizations can work together to successfully meet the needs of their communities. The project goal is to establish proof of concept with a small number of nonprofits. Future Mighty Missions 2.0 will allow organizations to connect with each other, see the success stories of other organizations, and include a group page. It will also feature a news feed of key articles and information related to their cause/mission.

Technology Stack: Flask, HTML, CSS, Python, SQLAlchemy, unittest, Postgresql, Jinja, Bootstrap

More About Sherry Matlock’s Bright Paths Project: Might Missions

 

Susmitha KristamSusmitha Kristam’s Bright Paths Project: Yummy Recipes

Outside of Hackbright Academy, Susmitha is a loving and doting mom eager to take part in her children’s activities, including leading STEM programs like a Science Olympiad and Math Pentathalon at her local elementary school. Prior to starting her family, Susmitha worked in quality assurance at a major healthcare group where she wrote SQL queries to query databases for testing. This experience sparked her interest in coding and a desire to pursue a new career path in software engineering. Prior to Hackbright Academy, Susmitha completed a Hackbright prep course and online self-study courses like Udemy’s Python curriculum.

Bright Paths Project: Yummy Recipes

With Yummy Recipes, users can find new recipes based on the ingredients and small appliances they have on hand. Users simply enter an ingredient or small appliance into the platform’s search function to find recipes that incorporate those materials. Nutritional information, type of cuisine, prep time, and cook time are also provided. Registered users can also create their own recipes, add recipes to their favorites list, and write reviews of other recipes.

Technology Stack: Python, PostgreSQL, JavaScript, Jinja, Flask, SQLAlchemy, HTML/CSS, Bootstrap, jQuery | APIs Used: Spoonacular/RapidAPI

More About Susmitha Kristam’s Bright Paths Project: Yummy Recipes

 

Yuliana AldrichYuliana Aldrich’s Bright Paths Project: Forever

Yuliana is excited to be starting a new career path in software engineering. Prior to starting the Perficient Bright Paths Program through Hackbright Academy, Yuliana worked in office administrator and project supervisor capacities where she managed groups of up to 50 people and developed 24 projects, including viable water and basic sanitation programs for the Guatemalan government. Her goal is to use the computer science skills learned to create, interact, and deliver projects that cover every client’s need. In addition to Hackbright Academy, Yuliana has completed self-study of basic concepts focusing on JavaScript, among other technologies.

Bright Paths Project: Forever

Forever is an app created specifically for couples. Using the app, couples can create an account, share and view information about each other, and exchange information with each other, such as requesting tasks to be completed and marking these requests as completed when a task is finished. Users receive a compliment of self-love on the welcome page when opening the app and can also find tips to grow closer with their partners.

Technology Stack: Languages: Python, JavaScript (AJAX, JSON), HTML, CSS, SQL. Framework & Libraries: Flask, jQuery, Bootstrap, Jinja, animate.CSS. Database & Industry Tools, PostgreSQL, Git, Github, Command-Line | APIs Used: Data scrapping

More About Yuliana Aldrich’s Bright Paths Project: Forever

We are blown away by the talent in the first Perficient Bright Paths class and wish each student success as we all take one step closer to helping close the gender gap in the tech industry. 


READY TO GROW YOUR CAREER?

At Perficient, we continually look for ways to champion and challenge our talented workforce with interesting projects for high-profile clients, encourage personal and professional growth through training and mentoring, and celebrate our people-oriented culture and the innovative ways they serve Perficient and the community.

Visit our Careers page to see career opportunities and more!

Go inside Life at Perficient and connect with us on LinkedInYouTubeTwitter, and Instagram.

]]>
https://blogs.perficient.com/2021/05/27/bright-paths-students-bring-ingenuity-to-custom-app-development/feed/ 0 292819