Releasing Mobile (React Native) Artifacts with Config File - android

Taking inspiration from The Twelve-Factor App: V. Build, release, run, I'm working on updating our CI/CD pipeline with these three distinct steps in mind for an app being built with react-native-web.
Specifically, I want to:
Build: generate an environment agnostic artifact of the code for each platform (web, android, ios)
Release: take an artifact and a config file (API URLs, API keys, debug settings, etc), and release to each platform
This is trivial for web, which is what The Twelve-Factor App had in mind. My question is how do I read a config file on mobile platforms and how can I incorporate this with react-native-web build artifacts? Does my artifact need to contain all of the source code and dependencies so I can pull in the config at release time and build then?
Ideally, each artifact would contain code compiled for each platform that somehow knows how to pull in a config file and do something with it. Next best would be to have the source code for each platform that I can compile with a config file at release time. Third best is have a way to give each distribution enough information at release time so it can request the config at runtime.
Full disclosure, I know nothing about building and deploying mobile apps so I apologize if there is an obvious solution for this!

It's similar for Android. Once the build binary is created it's immutable.
So unfortunately that negates option #1. We can't do anything else with the binary once we build it.
I think for react-native option two is the best approach.
Essentially you'll need to build the apps at release time once you have resolved what your configs need to be. That avoids any overhead of loading stuff at runtime in option #3 and still matches nicely to Twelve Factor. You'll still have a mobile binary that matches the same configuration as your release type.
For actually reading those values, you can just drop the config file into the project's root and we can help with the setup to pull them in.
I'll be glad to discuss those details if you'd like.
UPDATE:
Anything iOS does we can do (almost as well)
Current build tools compile all code into bytecode classes.dex and compress all resrouces into resrouces.arc but res/raw is left untouched.
This gives us a place to inject our files.
From there, the app will be able to read and parse at runtime.

For iOS, the build and (non-App Store) release process works like this at a high level:
Archive your project in Xcode, which results in an .xcarchive artifact.
Export your archive which signs and generates an .ipa file.
Either host this .ipa file yourself (with some additional metadata files) or upload it to a service like HockeyApp for distribution.
There are a few ways that you can manage config inside an Xcode project. One fairly common and straightforward way is to use the info.plist file to store custom keys and values. The app can then look up and use these values at runtime.
In the scenario you describe, it sounds like you want to be able to inject specific config values after step 2 but before step 3. Fortunately, the .ipa file generated during step 2 can be extracted, which will reveal a Payload folder containing an .app file. This file can be inspected, and inside you will see, amongst other things, the app's Info.plist. Modifying this file will allow for injection of whatever config values you want to set.
This will save needing to manage configs inside the Xcode project, and creating a separate archive for each configuration of the app. However what this doesn't solve is step 3. You are still going to need to distribute each configured .ipa file separately.

Related

How to include debug symbols for a pre-built native library inside an Android App Bundle?

Background info
When uploading an app to the play store that uses a native library its necessary to also upload the native debug symbols to get useful crash/ANR info.
If you upload without symbols you receive the following warning: "This App Bundle contains native code, and you've not uploaded debug symbols. We recommend you upload a symbol file to make your crashes and ANRs easier to analyze and debug."
In the past when uploading apps as .apk files it was necessary to manually upload such debug info. Now using .aab if the native library is built via android studio its possible to set android.defaultConfig.ndk.debugSymbolLevel = 'FULL' at which point when you build a the .aab it will include the debug info automatically, you upload this single file and everything is done/working.
pre-built libraries
However its not always possible/ideal/necessary to build a library inside android studio. Sometimes there are reasons for libraries to be externally pre-built and just used by android studio not built by it; Android studio supports this via a directory structure which is described here https://developer.android.com/studio/projects/gradle-external-native-builds#jniLibs
In short you just copy the libraries into the correct src/main/jniLibs/{ABI} path(s) and it is picked up and made part of the bundle.
Problem
Android studio can build a .aab that contains debug info that play store can understand so that you don't need to upload it manually.
Android studio can use pre built native libraries if you place them in the right path structure
I am unable to find any documentation or way to do both of these things together, use native pre-built libraries but include their debug info in the .aab. Even though logically it should be possible to do this.
I have searched everywhere I think but can't find anyone even talking about this really, how/where do you place the corresponding debug information so that that also can be included as part of the .aab? Is there a separate path for this, do they just need a specific file extension, does gradle need to be told what to do with them somehow?
Is it really just not possible?
Things I have tried:
Don't split the debug info just leave them in the .so files - play store does not strip them then so you deliver giant debug versions of your builds to your users
Split the debug info into files with .so.dbg extension and place them alongside the .so files - they aren't included in the .aab
Following the instructions (here https://support.google.com/googleplay/android-developer/answer/9848633 and elsewhere) to manually zip and upload the symbols after uploading the .aab - this appears to work but isn't the same convenience wise as having them in the .aab
I've tried building a sample app with android studio building a lib instead of using a pre-built lib just to verify that it does then include the debug info and what file extension it uses.
After some more digging I found the task responsible for this is "ExtractNativeDebugMetadataTask" with which some effort can likely be tailored/altered to do custom things here.
However this ended up being unnecessary as while digging into this I discovered that it actually already works.
At least as of now in latest gradle versions (not sure about the past).
It was only failing due to some NDK path confusion which doesn't fail the build/creation of the bundle building but just logs an easy to miss informational message.
Ultimately all you need to do to make this work is:
Build your external .so files with -g -g3 or similar
Do not strip them in any way
Place them in jniLibs directory structure un-stripped
Configure your build.gradle appropriately android{ ndk { debugSymbolLevel 'FULL' } ndkPath "$projectDir/path/to/NDK" }
Resulting .aab will contain the stripped .so files and the split-debug .so.dbg files all in the right location.

What is the Structure/Architecture for White Label Application

I am preparing a white label application (called product later in this post) and I want to set up a very good architecture. This will easily and quickly set up a new client by changing the design, activating features...
I have several servers (dev, pre-prod, prod) so the flavorDimensions server are present in the product and the flavorDimension client is on the client side.
I thought of this solution:
Set up one git per customer and one git for the product.
Clients will have access to the product code by git submodule. This allows me to separate the specific code from my client and the source code of the product.
Git -> Client 1
Submodule -> Product v1
Git -> Client 2
Submodule -> Product v1.2
...
Git -> Product v1.4
But I have a problem how to run it all correctly. The use of flavorDimensions client is hard because I need to make a copy-paste (with gradle) from my submodule to the app module before the build.
The generation of this structure breaks Gradle because its need to be synced every time. (Always Sync Now flag on Android Studio)
So I ask myself, is a good architecture or not ? What do you think ?
Or do you have other ideas and how to implement them?
Thanks for your support.
Hmm interesting take on it.
I have done similar things, but not quite like that. I use flavors for the deltas only. For example, themes, skins, app_icons, and Strings.xml. Maybe a few variations in layout or activities, but do my best to keep it generically served to minimize the maintenance of the code for various customer deployments as each additional flavor slows down the CI process significantly.
However, one key difference in what you are doing is you are not building a platform (aka everyone uses the same code GIT repo and API Server per se, you are building stand alone applications to supply full code and everything else to individual customers.
This sounds like it could be a maintenance nightmare, but if your situation requires that customer's get access to the code base for their product flavor, then I guess it makes sense. Not sure why they would get access to the code though as it is your product you are reskinning for customers right?
At any rate, you aren't asking for me to ask your reasoning haha, you are asking about architectural solutions. So here is my thoughts.
Make a task that copies the respective folders into a new module structure exactly like the modules you have now, but with changes to the package name so that they all slightly differ, then run your GIT push. You can run bash files from Gradle, so you can either write scripts and execute them from relative paths or you can write it directly in your Gradle file itself.
So I would update my Gradle to have separate dependency file like libs.gradle
->Put dependencies in that file like ext.libs {gson:"com.whatever:version"}
->apply from ../libs.gradle
->dependencies { libs.gson, etc..}
So i would assume your build task would do
->Create a new Module from All Source by copying files properly with new names if necessary to rename
->if using maven server, then deploy aar or jar for compiled new module
->Create a new dynamic Gradle file libs.gradle to replace current libs.gradle file that is updated source pointer to deployed artifacts
or created module
->run gradlesync, when complete run assembleRelease, then you can do your git push etc..
All of this can be synchronized and done from terminal and localized into commands. Flavors may not help a ton in this area as they are part of the build process so you kinda need pre build processes which you can create tasks to do pre-build, but the key is the packaging of dependencies and updating your libs.gradle file and making sure that you replace it per flavor. Or if you have fixed flavors you can just make a specific libs.gradle for each flavor and update it based on the compiled dependencies.
I don't know your overall picture, but it is all doable. Hope that helps. Goodluck.

How to handle assets for different Product Flavors

I have the following problem wherein:
I have multiple product flavors In my Android project. {Say, Dev and Production}
I have a CI in place ,Jenkins to build my projects and make releases to different teams.
I have an asset file which is Flavor Specific, but is dependant upon the data that exists on a server. Example a json for a list of companies.
This list is different on Dev vs Production.
Since this is a huge json, we include it in our assets folder. Downloading this json at runtime will not allow the user to use the app quickly at least the first time.
Currently at compile time in Jenkins we wget/download this json and write them to our assets folder. To get the latest assets for that environment/product flavor at compile time.
This wget is written as a shell command in my Jenkins. After a successful wget we run the gradle assembleDev, repeat step 6 and then gradle assembleProduction
Now the problem lies with the fact that I am not comfortable having this wget in Jenkins for 2 reasons.
1) The Environment specific asset/json is not available on developer machines for their local testing, so they need to be aware all the time.
2) The code in Jenkins is obviously not present in my VCS/Git. Which I am not comfortable with.
What could be the possible solutions?
PS:- To put things in perspective, I have 22 Product Flavors and 8 such jsons.
In our production setup, we currently parse a Google Sheets document to find variables and write them into our strings.xml file.
So a some-what similar scenario.
We do this in our Gradle build script, that calls a Java class, that then executes the network logic, returns the downloaded data to Gradle, which writes it into the correct strings.xml file.
This means all of our code is present in our git repository and can be handled as such.
I find this to be quite elegant.
Note: We currently don't differentiate between product flavors, but that is easily done with a few extra lines in Gradle.

Incremental build for Android project using Ant

My server needs to keep building a large amount of Android projects. All of them are almost identical except for minor change on manifest.xml or any resource file (if it's better for the task) for each build. To reduce cost and improve efficiency, I try to implement incremental build. My planned procedures are:
after the first successful build, skip all the previous
procedures (aapt to generate R.java, adle to make java, etc.)
directly call aapt to make resource files, e.g., *.ap_
call apkbuilder to make classes.dex and usigned.apk
make signed.apk
So my question is whether the above solution is possible? And any clue about how to implement it?
This isn't necessarily a solution for your particular requirements but perhaps it will provide you with some useful pointers.
I have an Antlib that I use for building Android projects. You probably won't want to use it yourself as it has some drawbacks, but it should serve as an example of how to perform the various steps to build an Android app using Ant. In particular, it shows how to call the various Android SDK tools from Ant and how to use the Ant uptodate task and Ant's if and unless attributes to avoid processing files that haven't changed.
The source for the Android Ant macros is here (the Antlib documentation might help you to make sense of what it's doing).

Android - don't want to decompile my apk file

I am developing an android email client application and Calling webservices using ksoap2 library and also writing some encryption algorithm to encrypt data in my client.
In some websites I have read "It is possible to decompile the apk using some decompilers". (i.e.) get the source code from apk file.
But I want to secure my code. Don't show the encryption algorithm code after decompilation or don't want to decomplile my apk file. Is it possible to do that? please can you give some suggestions?
Edit the file (in the project root) project.propierties and add the line
proguard.config=proguard.cfg
And its done. When you try to generate the signed apk of your app it will take a little longer and it will be obfuscated.
If you receive the "Conversion to dalvik error" when generating the apk you need to update the proguard of your sdk. For doing it you need to go to the ProGuard page to the download section. Download the last stable version and put it content in
SDK_ROOT/tools/proguard
Deleting the existing content before of course.
You can check the Proguard manual at their page (link is above) and the Android's Proguard page for more info about ProGuard
This process is known as Obfuscating the code.
EDIT:
Steps to get obfusticated apk:
1) Download latest proguard from "http://sourceforge.net/projects/proguard/files/". Current latest version is proguard4.7
2) Replace "bin" and "lib" folder of "C:\Program Files (x86)\Android\android-sdk\tools\proguard" with latest downloaded proguard folders.
3) Check SDK location in eclipse for blank spaces in it and for that go to window > Preferences > Android. If there is blank space then replace it with:
c:\Progra~2\android\android-sdk (for windows 64-bit)
c:\Progra~1\android\android-sdk (for windows 32-bit)
4) Check that proguard.cfg file is in your project's root folder and add "proguard.config=proguard.cfg" in project.properties file of android project.
5) Now export your project to get obfusticated apk.
I hope that it will help.
You must not rely on security through obsurity.
If you feel that the encrypted data would be compromised by the knowledge of the encryption algorithm, then you're NOT doing security.
It will always be possible to decompile any file, if the "hacker" knows how to do so. That's why there are still cracks for paid applications, because people take their spare time to decompile/crack applications. All you can do is to make them have a hard time by using as many tools as you can. The first choice (and that comes disabled by default) is ProGuard

Categories

Resources