Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

android build: Update to AndroidX. #3852

Merged
merged 1 commit into from
May 8, 2020
Merged

Commits on May 8, 2020

  1. android build: Update to AndroidX.

    AndroidX, previously called the Android Support Library, is a
    collection of libraries developed by Android upstream which are
    bundled into an app at build time, rather than taken from the system
    on the device.  Some are quite central to a typical Android app.
    
    Upstream has renamed the whole thing to AndroidX, and this goes
    with a renaming of tons of classes.  (Mostly to get them out of
    `android.*`, which was always very confusing because that's the
    same namespace used by the actual system packages.)  Docs:
      https://developer.android.com/jetpack/androidx/migrate
    
    This could have been sticky, because lots of apps and lots of
    third-party libraries refer to these core libraries, and in a
    distributed ecosystem it's impossible for everything to update at
    once.  And because these are often so central, a given build of an
    app must use the same version of them throughout -- including from
    any third-party libraries it uses.  So for example if some
    third-party library has updated to use AndroidX, then an app cannot
    switch to that version of that library until it too has updated to
    use AndroidX.
    
    Fortunately, the planners of this migration recognized this could
    be a problem, and found a way to make the constraints run only in
    that one direction.  When an app updates to use AndroidX, it can do
    so even while it's still using third-party libraries that are still
    built to use the Android Support Library.  The key is a tool called
    "Jetifier", described in detail here:
      https://developer.android.com/studio/command-line/jetifier
    To use it, we set the flag `android.enableJetifier=true`, and then
    (quoting the AndroidX migration doc linked above):
    
      The Android plugin automatically migrates existing third-party
      libraries to use AndroidX by rewriting their binaries.
    
    So the migration path is, apps go first; then libraries update at
    their leisure.
    
    ---
    
    For us, the most important third-party library (third-party from an
    Android perspective) is React Native.  RN took the AndroidX update
    in v0.60, so we have to do the same before we can complete that RN
    upgrade, i.e. zulip#3548.
    
    The Android upstream way to update a given project (as described by
    the doc linked above) has two prongs:
    
     (a) The project's own source code can be updated automatically
         (barring fancy use of classloaders, etc.) by Android Studio,
         with the feature "Refactor > Migrate to AndroidX...".
    
     (b) Third-party libraries get updated when they're linked in, by
         rewriting them as part of this project's build.
    
    Both of those appear in this commit.  But in an RN context, there's
    one other important set of code: third-party RN libraries get
    pulled in as part of *our* Gradle build, with build.gradle lines
    using `project`, like so:
        implementation project(':react-native-vector-icons')
    This means they're not covered by (b).  This contrasts with RN
    itself, which is pulled in as a binary artifact:
        implementation "com.facebook.react:react-native:+"
    
    So for those third-party RN libraries, we need to edit the *source*
    code, like (a), before it gets built.  Happily, someone has written
    a tool to do just that, and we use it:
    
     (a') Third-party RN libraries get rewritten in place in
          node_modules/, after `yarn` installs them and before the
          Gradle build.  This uses a different "jetifier" tool:
            https://github.com/mikehardy/jetifier
    
    Specifically, the latter "jetifier" will crawl node_modules; find all
    .java, .kt, and .xml files; and apply a list of string substitutions
    (about 1900 of them) to rewrite old names to new ones.  That sure is
    kind of heuristic... but it's good enough that it will in fact find
    any normal import of the affected classes, and on the other hand the
    patterns being substituted are all long boring fully-qualified Java
    class names, unlikely to be found in spurious places.  For us, I
    also inspected (below) the exact edits the tool makes.
    
    ---
    
    In this commit, we take the upgrade.
    
     (a) I used "Refactor > Migrate to AndroidX..." in Android Studio.
         This updated a few spots in our own source code.
    
     (b) The same auto-refactor added the `gradle.properties` settings
         (in particular enabling Jetifier, the Android-upstream tool)
         that handle libraries we incorporate as binary artifacts,
         including RN itself.
    
         It also updated dependencies in our `app/build.gradle`.  This
         made the `supportLibVersion` variable unused, and I deleted it.
    
     (a') We add `jetifier`, the NPM-world tool, as a dev dependency,
          and invoke it in our `postinstall` hook.  This means any run
          of `yarn install` (or bare `yarn`) will end by running it.
    
    I inspected manually (by making copies of `node_modules`, and
    comparing with `git diff --no-index`) the effect of `jetifier`.
    All the edits look appropriate.  Excluding a few that have no
    effect, the edits appear in the following packages:
      react-native
      react-native-image-picker
      react-native-webview
      react-native-photo-view
      rn-fetch-blob
      @react-native-community/netinfo
      @unimodules/react-native-adapter
      unimodules-image-loader-interface
      expo-constants
      expo-file-system
      expo-permissions
    
    (FTR the other edits were in react-native-notifications, which on
    Android we don't use or build, and in react-native-device-info and
    react-native-sound, limited to IDE metadata plus copies of parts of
    the support library itself in build-intermediate directories.)
    
    So once we've upgraded all of those to versions that use AndroidX
    in the first place, the `jetifier` tool should become a no-op and
    we can delete our references to it.  (It won't go away entirely,
    because RN v0.60 has `react-native run-android` run the tool; but
    it'll stop mattering.)
    
    I tested the app in both debug and release builds, and exercised
    relevant dependencies: picked and uploaded an image; opened the
    lightbox; downloaded an image there; entered and left airplane mode
    to see the "No Internet connection" banner.  Together those cover all
    but the unimodules and expo dependencies; I'm not sure we actually
    use each of those anywhere at all, but I exercised the core unimodules
    machinery by going to the diagnostics screen to view the app version,
    which uses an Expo unimodule.  Everything I tested works.
    gnprice committed May 8, 2020
    Configuration menu
    Copy the full SHA
    e433197 View commit details
    Browse the repository at this point in the history