I'm new to software dev, so I don't know the proper etiquettes for this process.
I just want to keep certain debugging code (comments and stuff) and maybe some testing resources like images after cleaning an app for release. These are things the app will never need for functioning, just stuff I wanna keep.
Are comments kept after the compile? If not I can just comment out those lines.
I thought about using different flavours, but it doesn't seem appropriate? Just because the build release type makes 4 options.-which I never really understood. Does switching from Debug mode to Release mode change anything code-wise? Like other than the signing methods and other discrete (discrete to me anyways) changes?
Thanks!
Are comments kept after the compile? If not I can just comment out those lines.
Commented-out code isn't compiled, so if you want, yes you can comment out code and it won't show up in the final app. However, there's no way to comment out resources in the same way, so if there are resources you only want to have in your debug version, keep reading.
I thought about using different flavours, but it doesn't seem
appropriate? Just because the build release type makes 4 options.
You're right, you don't need flavors because there's already build types (Debug and Release) which are set up to do what you want. Your Java code can tell the difference between debug and release types via the BuildConfig class, which is automatically generated as part of the build. It has a DEBUG Boolean constant that's defined to true for debug builds and false for release. So you can have code that does something like this:
if (BuildConfig.DEBUG) {
// Do something here that you don't want to have in the final release
}
Since BuildConfig.DEBUG is a static final Boolean, then Java is smart enough to see that what's inside that if block will never run in a release build, so the compiler will strip that code out and it won't appear in your app.
If there are resources you'd only like to have in the debug and not release versions of the app, then you can put them in a different folder in your hierarchy:
ProjectDirectory
+--app
+--src
+--main
+--res <--Your normal resources go here
+--java
+--AndroidManifest.xml
+--debug
+--res <-- Put resources for the debug build only here
That debug/res folder won't be created by default, but if you set it up, the build system should pick it up. Having said that, debug-only resources are a little unusual; you would only have something like this if your debug version of the app had something like a diagnostic activity or menus or something like that. It's certainly possible, but it's a little more advanced than it sounds like what you're doing so far.
-which I never really understood. Does switching from Debug mode to Release mode change anything code-wise? Like other than the signing
methods and other discrete (discrete to me anyways) changes?
Some of the important changes in a release build are:
BuildConfig.DEBUG will be false as already noted.
Your app will be signed with a release key instead of the debug key. The release key is what you will use to sign it to upload to the Google Play store. You'll need to set up that key if you don't have it already.
Release apps are built as non-debuggable unless you change the setting.
You can run ProGuard (which does dead code stripping and obfuscation) on release builds, though it's not configured to run by default.
Related
how to enable logger in specific screen of release-build in android?
I Realeased an APK in playstore which is obfuscated apk and Logger are disabled , When customers find some issues in that apk in specific screen. So i want to Enable Logger in that specific screen of release-build.
Is it possible, If Yes how can i acheive..??
Updated Question:
Apk release build - Obfuscated by DexGuard
Thanks
You could use Log.i. Information logs are always showed to users. See more.
If you used ProGuard to remove all logs from your application you should remove clearing of public static int i(...); from rules.
If it wasn't enough flexibility try Timber
And setup ReleaseTree for your release versions
It is not possible to enable logger in release builds. Instead of that you can use this lib to print log on your screen.
Another solution you can find an example of it here. It's really simple, just add a class OnScreenLog to your project
My Android app is coming to the end. Debugging runs OK for many many times without any error. It runs just fine. It's the time for me to build a release and publish the app. I follow all the steps which can be found via Google easily. In fact the signed APK is installed OK and the app starts OK but if user interacts to navigate between screens of the app, it is crashed for no reason. Not all screen switching causes app crash, just some of them and I can notice that maybe it involves Reflection here. I design my own binding system to bind ViewModel behind with the Fragment and using Reflection is a must, no other way.
I totally believe that it is not any fault in my code because the app runs just fine in debug mode. And at the time of nearly completely losing all hope to publish the app, I found a signed version of the APK file in the debug folder (that signed version is generated only if you start debugging the app to run in some targeted device - even some emulator, building in Debug mode won't generate that file). It's very lucky for me that that signed apk works perfectly. I can deploy that APK to a new device and install normally, the app runs expectedly.
So it must be something wrong with the releasing process. Here is some info about configuration for Release mode (mainly in Android Options tab):
Packaging (Packaging properties): Nothing is checked in here.
Linker: I tried both Sdk assemblies only and Sdk and user assemblies but nothing works.
Advanced properties: I checked all options to support all possible CPU architectures (this should not be a problem because in debug mode, all these options are also checked).
At the beginning of learning Xamarin Android, I tried finding information about publishing Android app and did complete a simple test (to deploy a simple app). It worked OK at that time (maybe because it's too simple), but now when it comes to a complex one (mainly involving my binding system which uses reflection heavily) it can be crashed at some user interactions. I also have a separate library project (containing some custom Views) referenced OK in my main project (not sure if that could be a break, however one custom view is used OK while some others may cause crashing). Because all the crashes happen in a compiled build, I cannot debug anything to see what could be wrong.
No code is provided here because there is too much code, it seems to be crashed at many places and one more important reason is the code should not be the problem (for one reason I explained above - it just runs smoothly in debug mode, I even found a signed APK file in debug folder which can be installed OK and the app then runs just OK like in debug mode).
Since you stated you are using a lot of reflection, the first thing to do is:
In the Android Build Settings:
Disable Proguard if it selected
Change the Linker Options to Don't Link
Rebuild a release build
Update: Since this worked and the app no longer crashes.
The linker will sometimes remove code that you want to preserve.
For example:
You will need to determine what classes and/or method are being remove because that have no direct references and are only called via reflection and preserve those to prevent the linker from removing them.
If they are in your code, you can use the [Preserve] attribute.
If they are 3rd party libs or the Xamarin.Android framework, you can create a "hardcoded" fake reference to those classes/members so the linker sees that you need them.
You might have code that you call dynamically via System.Reflection.MemberInfo.Invoke.
If you instantiate types dynamically, you may want to preserve the default constructor of your types.
If you use XML serialization, you may want to preserve the properties of your types.
Ref: https://developer.xamarin.com/guides/android/advanced_topics/linking/
My situation is that I want both free and full versions of the same Google Play Store (GPS) app. To satisfy GPS, I had the choice of figuring out GPS API for in-app purchases or creating a second package. I chose the latter path since the former was far from easy to follow (couldn't implement after trying for parts of 3 days).
Before realizing that a second package would be necessary, I had designed the app so that merely changing two imports (package names), one boolean assignment (FREE: true or false), and a couple of lines of AndroidManifest.xml (icon and app name) I could easily change the code from free to full and back again.
All well and good. Then came first bug: actionbar overflow "dashes" didn't appear on a tablet.
So I have two hunks of 99%-identical java and xml code. When I find the need to change code in future, I don't want to have to make two probably-identical changes. And figuring out the GPS API is not likely to penetrate my brain anytime soon.
In trying to answer my own question before posting, I just ran across this here, without further explanation:
I was using Android Libraries to build Free/Paid versions of my app. [With] the new Gradle Build Variants concept... you can now automatically build different signed APKs out of the same code.
It received an upvote, but that doesn't make it credible.
Is it?
If it is, I'm also not sure if it applies to me. The message from GPS when I made the changes alluded to earlier within the same package was that I needed different package names for the free and full versions, and that quote doesn't mention packages, although maybe it's a way around separate packages. I wish I knew.
If the quote applies to having ONE package upload TWO versions of an app to GPS, what do I have to do to make gradle do so?
EDIT--
I was sure there was no way until I found this. Is this a way to avoid near-duplicate apps and packages?
Yes, Build Variants are the answer to your problem.
First, I recommend reading the Build Variants documentation on the Android tools site.
What you want in the end is two product flavors. Inside each product flavor closure you can specify the applicationId (formerly packageName) for that flavor. Your build.gradle will look something like this:
productFlavors {
paid {
applicationId "com.example.paid"
}
free {
applicationId "com.example.free"
}
}
When you build your app, you will now get an APK with every possible combination of product flavor and build type. These are called build variants. For your app, you will probably end up with something like debugFree, debugPaid, releaseFree, and releasePaid variants.
You just upload the releaseFree and releasePaid APKs to Google Play (as separate apps) when you want to release.
As for your issue of having duplicated code:
When you create a new product flavor or build type, you can create a set of source files (resources, Java classes, etc.) to go along with that flavor.
By default, all your code goes into the main source set (this is the main folder in your project).
If you want to add some Java classes that provide different functionality for your free variant, you can put those classes in <project root>/app/src/free/java instead of <project root>/app/src/main/java.
For example, you might put a FlavorConstants class containing your boolean flag in both the free and the paid folders. Whenever you reference FlavorConstants in your code, it will be the correct FlavorConstants for whichever flavor is currently running on your device.
I'm looking for a simple way to make sure my static final boolean DEBUG flag is set to false when exporting my Android project to APK.
I've tried using the "STOPSHIP" comment marker mentioned here, but it doesn't seem to have any effect on apk export, or I'm using it wrong.
Building a lint extension seem an overkill for such purpose, is there a simpler way to do it?
Edit
Using the auto generated BuildConfig.DEBUG flag, combined with some hard to miss on-screen indication that you're running in debug mode (plus a mental note never to upload apk's at 4am after a quick fix) - will probably have you covered.
BUT it is still not the 100% fool proof method I posted this question for.
There are still complaints about BuildConfig.DEBUG randomly not functioning as expected.
So This question is still open - is there a lint trick, or similar trick to do it?
Starting from Android Gradle Plugin 3.0 you can make following configuration in build.gradle file:
android {
lintOptions {
fatal 'StopShip'
}
}
This will break the build as long as there exists a StopShip comment in codebase.
Watch the exact minute of Tor Norbye's "Kotlin Static Analysis with Android Lint" talk, where he talks about the feature.
Have you solved this? I know 2 years have passed, but I just found this while searching what was STOPSHIP after finding it by accident while commenting.
StopShip
--------
Summary: Code contains STOPSHIP marker
Priority: 10 / 10
Severity: Warning
Category: Correctness
NOTE: This issue is disabled by default!
You can enable it by adding --enable StopShip
So I would say you should have executed the command in order to enable it.
I've been using this flag reliably for several years now:
BuildConfig.DEBUG
It doesn't have the issues that occurred long ago, when I posted this question.
You could modify the build.xml, have it read your DEBUG flag from the source and simply change the file name of the APK depending on the value. Make that name explicit enough and you will never distribute or upload the wrong APK (and you can also make it a condition for other following automated processes).
I have created a custom build script in python that changes some strings in my strings.xml. But now I need it to change some other strings depending on whether it is a release or debug build. I can't seem to find a variable that I can send as parameter to the script that differentiates between the two.
I want to avoid going over to ant if at all possible, since we have build servers and all kinds of stuff that need changing then too.
Does anyone have experience with this?
One way to do this is to test the app's signature at runtime. You could load different strings based on that result:
How to make Android app automatically configure w/ debug vs. release values?