Search code examples
androidandroid-gradle-pluginandroid-buildandroid-build-flavors

Multiple APK versions with different functionality


I'm developing and app which will (during the development and testing process but NOT in the final version) require slightly different functionality in different .apk release files.

There are few issues in this particular case:

  • different "testing" APK versions shouldn't contain ANY of the code and resources (so no shared strings and images) from other APK versions (for security/reverse engineering reasons cause different people will have access to different APK versions)
  • at the end of the development process the app will contain all/most of the features from the "testing" builds.
  • the app uses multiple modules (developed by different teams)
  • there might be a few (between 3 and 10) of those versions, all developed concurrently by multiple developers in the same project on the same repository.

The goal is to make it as easy to maintain (including UI/integration tests and CI) as possible. Is there any way to achieve this? We did some experiments with different build variants and flavours + no-op modules/methods but it seems a little bit complex. Any alternative suggestion will be welcomed.


Solution

  • Your question is indeed too broad, I think there is no general solution to your problem because it's too complex, and without knowing the details of the project it's even more difficult to tackle. Actually, your problem sounds much more like an organizational one rather than a programming-related one, the only "solution" I see is to address specific issues.

    1. No VCS, no party

    there might be a few (between 3 and 10) of those versions, all developed concurrently by multiple developers in the same project on the same repository.

    I would start by defining your VCS flow, because without a version control system I'm afraid you and your team(s) aren't going anywhere. If you were to use git (don't know how this would be done with other VCS), you would have a few options:

    1. Each feature (team) has its own, long-living, feature-branch. The common code shared by all teams is kept on a develop-branch, on which each feature-branch periodically rebase. You would need to setup your CI to build test apks and run automated tests for each branch. At the end of the development process everything gets merged into master (or develop, or whatever). The advantage would be that each feature (team) would work on a sealed portion of the project and will be able to handle test releases and automated tests autonomously. The disadvantage would be that the common part of the codebase (develop-branch) needs to be handled very carefully, otherwise you might get conflicts-hell.

    2. The whole project is developed on a common develop-branch. Each feature is developed with small increments, each member of each team branches from develop-branch and merges every iteration back on develop-branch. The advantage would be: different features can potentially depend on each other, conflicts are less likely to occur, CI has simpler configuration. Disadvantage: teams are less independent, releasing different apks requires a strategy.

    2. Define dependencies

    In order to choose a proper strategy, it is crucial to define clearly the dependencies between the features. Would it be possible to have truly parallel development of each feature?

    This depends entirely on the specification of the project. For instance, if you were to develop an e-commerce app, you might end up having feature domains like user account, products catalog, orders processing... If all of these features depend on common local storage layer, how are you going to develop them truly in parallel?

    Once you've defined the dependencies, you will be able to decide in what degree the features can be developed in parallel. Do different teams need to agree on common interfaces? Could a feature be completed even if other teams are still at 0?

    3. Build variants are your friend

    different "testing" APK versions shouldn't contain ANY of the code and resources (so no shared strings and images) from other APK versions (for security/reverse engineering reasons cause different people will have access to different APK versions)

    Flavors are meant to do exactly what you're looking for, that is, build different apks from the same project but using different subsets of code and/or resources.

    Keep in mind that you can have flavors in multiple dimensions (and build types). For instance, you could have one flavor dimension called "network", with 2 flavors "mockedNetwork" and "actualNetwork". Then you could have another dimension "feature", with "featureA", "featureB", "featureC". You could then easily build and release 6 types (well 12 if you have also debug and release build types) of apks, one for each combination (mockedNetworkFeatureA, actualNetworkFeatureA, mockedNetworkFeatureB etc.).

    With flavors you could easily replace chunks of the app that you don't want your tester to have. For instance, you could have a strings.xml file with only lorem ipsum strings and then keep actual texts strings only for internal use.