How we migrated MileIQ Android + React Native app to AndroidX

This post has been republished via RSS; it originally appeared at: Android@Microsoft - Medium.

MileIQ is a mileage tracking app which automatically tracks drives for classification as business vs. personal. For users, it eliminates the time to track drives with a written log, produces the required documentation for tax purposes, and can save them money by maximizing their tax deduction and/or company mileage reimbursement. For companies, it can also save them money by ensuring the proper amount is reimbursed, and/or provides the required tax documentation for vehicles they may deduct.

Why did we migrate to AndroidX?

  1. In MileIQ, we also supported Microsoft AAD (Azure Active Directory) users for enterprise scenarios and we were using ADAL library for authentication of AAD users. Azure Active Directory (Azure AD) is Microsoft’s cloud-based identity and access management service. More details around Azure Active Directory can be found here. We were facing few issues in production with respect to authentication of AAD users. Since the ADAL library was being deprecated, the fixes for the login issues were shipped as part of the MSAL authentication library. As the MSAL library was AndroidX compatible, it required us to migrate our app to AndroidX.
  2. The MileIQ app was a hybrid app and we used React Native tech stack to build few workflows in our app. The React Native version that we used was < 0.60 and we were planning to migrate the version to >0.60 as it promised a better performance, developer experience and lower app footprint. Since from version 0.60 onwards, RN supported AndroidX, this required us to migrate our app to AndroidX.
  3. Last but not least AndroidX is a major improvement over Android support libraries and the improvements and updates over support libraries were being shipped as part of AndroidX.

The dependency chart for MSAL library integration is shown below

Cascading Dependencies for MSAL integration

Migration Steps

Android Native Upgrade Steps

  • The first step that we took was to migrate the entire project by using the Android Studio “Migrate to AndroidX” project from menu bar. This option is available for Android Studio 3.2 and above. This step helped in transforming most of the support libraries dependencies to AndroidX dependencies. Additionally this step also adds two properties to the gradle file.
android.useAndroidX=true

This flag when set to true uses appropriate androidX library instead of a support library

android.enableJetifier=true

This flag when set to true uses jetifier tool to transform 3rd party libraries to use AndroidX.

  • The above step did not completely migrate the project to AndroidX. There were still few manual steps involved. We were using butterknife for view injection library which caused compile errors post migration due to the generated classes still referring to Android support libraries. We upgraded the library from v8.8.1 to v10.1.0 which supported AndroidX libraries to fix the same.
  • There were also couple of more imports which had to be updated from the layout xml files as shown below
android.support.v7.widget.RecyclerView to androidx.recyclerview.widget.RecyclerView
androidx.constraintlayout.ConstraintLayout to androidx.constraintlayout.widget.ConstraintLayout

React Native Upgrade Steps

  • Update React Native from version <0.60 to >0.60. This was a major version update, and involved lot of changes. Since we maintained separate repositories for React Native codebase and Native code base, we had to make the changes manually in the native side instead of using the “react native upgrade” utility. React Native upgrade helper is a good starting point if you are looking to upgrade your app’s React Native version.
  1. From version 0.60.0 onwards, React Native had deprecated certain packages from react native core and made it available as part of react native community. Due to this we had to manually integrate AsyncStorage, WebView and NetInfo packages from native side.
  • Update package.json file with community packages and install the node dependencies.
  • Update the settings.gradle file to include the packages
include ':react-native-code-push',
':react-native-webview',
':react-native-community-netinfo',
':@react-native-community_async-storage',
':react-native-community-netinfo'
project(':react-native-webview').projectDir = new File(rootProject.projectDir, 
'/node_modules/react-native-webview/android')
project(':react-native-community-netinfo').projectDir = new File(rootProject.projectDir, 
'/node_modules/@react-native-community/netinfo/android')
project(':@react-native-community_async-storage').projectDir = new File(rootProject.projectDir, 
'/node_modules/@react-native-community/async-storage/android')
project(':react-native-community-netinfo').projectDir = new File(rootProject.projectDir, 
'/node_modules/@react-native-community/netinfo/android')
  • Update the app build.gradle file dependencies section to include the react native community dependencies
implementation project(':react-native-webview')
implementation project(':react-native-community-netinfo')
implementation project(':@react-native-community_async-storage')
implementation project(':react-native-community-netinfo')
  • Include the community packages where the ReactInstanceManager is getting instantiated.
private List<ReactPackage> getPackages() {
return Arrays.asList(
new RNCWebViewPackage(),
new AsyncStoragePackage(),
new NetInfoPackage()
);
}

2. Updates to the React Native Code Base

  • Updated React from v 0.16.8.3 to v 16.9.0 and all the other related dependencies.
  • Updated all the imports for React Native WebView, AsyncStorage and NetInfo packages .
import { AsyncStorage } from ‘react-native’; //RN 0.59
to
import AsyncStorage from ‘@react-native-community/async-storage’; //RN 0.61.5
  • From v 16.9 onwards React deprecated the old names for UNSAFE_* lifecycle methods of React Components. Hence we had to update all the lifecycle methods of components with UNSAFE prefix. We used the following utility script to update of the lifecycle methods.
npx react-codemod rename-unsafe-lifecycles

Challenges

  • Since the migration was a huge change, we had to run multiple regression tests on the entire app. This helped us in catching few runtime crashes in few android native screens that were happening due to incorrect imports in the layout xml file such as “android.support.v7.widget.RecyclerView” instead of “androidx.recyclerview.widget.RecyclerView” and “androidx.constraintlayout.ConstraintLayout” instead of “androidx.constraintlayout.widget.ConstraintLayout”.
  • There was an accessibility issue observed when talkback mode was enabled. The items inside the coordinator layout were not getting focused post the migration. This got fixed after we upgraded the google material design dependency and included coordinator layout dependency as shown below.
com.google.android.material:material:1.1.0
to
com.google.android.material:material:1.2.0
and added
androidx.coordinatorlayout:coordinatorlayout:1.1.0

Impact

  • The AndroidX migration helped us in successful integration of MSAL authentication library and fix the authentication issues that were happening in production.
  • The React Native version update to >0.60 reduced the app download size from 27.4 MB to 20.5 MB and the app size on device by 86.8 MB to 78.2 MB
App Download Size From Android Vitals
App size on device from Android Vitals
  • This opened up the opportunity to integrate the latest jetpack libraries announced by Google.

Learning

  • Prerequisites: Ensure that the prerequisites mentioned in the android migration developer site are followed to reduce the manual steps.
  • Testing: The Android Studio migration tool does a good job of migration but it might not handle everything, hence after the manual migration of the app, it will be a good idea to thoroughly test the workflows of the entire app to avoid runtime crashes in production.

Credits

Thanks to Swathy Mothilal and Amit Singh for the help with the code review and testing .

Thanks to Cesar Valiente, Max Wheeler, Neal Bernstein, Jasbir Khalsa, Akshath Shetty and Sumita Jaiprakash for help with the article review and feedback.


How we migrated MileIQ Android + React Native app to AndroidX was originally published in Android@Microsoft on Medium, where people are continuing the conversation by highlighting and responding to this story.

REMEMBER: these articles are REPUBLISHED. Your best bet to get a reply is to follow the link at the top of the post to the ORIGINAL post! BUT you're more than welcome to start discussions here:

This site uses Akismet to reduce spam. Learn how your comment data is processed.