I want to perform a code operation only under the assumption that the current build is a signed APK. Is there a way to programmatically find out?
You can check to see if you're running a debug build with BuildConfig.DEBUG. If this shows up as false, you're on a release build. For example:
if (BuildConfig.DEBUG) {
Log.d(TAG, "This is a debug build");
} else {
Log.d(TAG, "This is a release build");
}
PackageInfo.signatures contains the array of all signatures read from the package file. This can be obtained using PackageManager.getInstalledPackages() with GET_SIGNATURES flag.
Related
Is there a way to check within my android application if it's being debugged, like a DEBUG flag or somthing? I want to print a special message when the application is being debugged.
You can use BuildConfig.DEBUG. This is a boolean value that will be true for a debug build, false otherwise:
if (BuildConfig.DEBUG) {
// do something with debug build
}
There are two ways to check if the apk is being debugged or not
1. BuildConfig.DEBUG:
if (BuildConfig.DEBUG) {
// do something with debug build
}
Note: If you are using the first one then make sure BuildConfig is imported from your project or your app.
2.ApplicationInfo.FLAG_DEBUGGABLE
if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE)) {
//Debug APK
}
I have this code at the end of my build.gradle file:
project.afterEvaluate {
// If you add/change build types, you have to add to/change
// these task names.
mergeDebugAssets.dependsOn project.tasks.getByName('downloadLicenses')
mergeReleaseAssets.dependsOn project.tasks.getByName('downloadLicenses')
}
See: Copy generated third party licenses to assets for the full code
This used to work fine (regardless of which buildType was set) but if updating my dependencies to the latest version this triggers an exception (when building with buildType='debug'):
Could not get unknown property 'mergeReleaseAssets' for project ':application'
My thought was that maybe split this block in two and put them under the buildTypes configuration. This doesn't work though, as it tries to evaluate the code anyway and crashes.
Any ideas?
Update 1: Root cause?
https://code.google.com/p/android/issues/detail?id=219732
Update 2: A horrible workaround:
try {
mergeDebugAssets.dependsOn project.tasks.getByName('downloadLicenses')
} catch (Exception e) {
// Expected when building variant Release
}
try {
mergeReleaseAssets.dependsOn project.tasks.getByName('downloadLicenses')
} catch (Exception e) {
// Expected when building variant Debug
}
The reason that you get an error referencing a release task in afterEvaluate is probably because Android Studio's Instant Run feature uses a special Android Gradle plugin feature to only build the debug application variant. This means that only the debug tasks are created, hence why the release tasks can't be found when you reference them.
There are several ways to deal with this:
Search for the dependent task by name using a string. If the Android build system changes the task name in the future, your additional build rules won't run, but you might not even notice.
To determine if release tasks exist, check for the existence of a task whose name is unlikely to change in the future. Maybe assembleRelease fits this bill.
To determine if release tasks exist, check if the release application variant is built with something like:
project.afterEvaluate {
if (!android.applicationVariants.matching { it.buildType.name == 'release' }.isEmpty()) {
mergeReleaseAssets.dependsOn project.tasks.getByName('downloadLicenses')
}
}
The last option looks kind of gross, but hopefully it will fail-fast if the Android build system task names change in the future.
The reason you get exception in case of debug buildType is because mergeReleaseAssets task is not created. You can do the following instead:
project.tasks.findByName('mergeReleaseAssets')?.dependsOn project.tasks.getByName('downloadLicenses')
or even omit project:
tasks.findByName('mergeReleaseAssets')?.dependsOn tasks.getByName('downloadLicenses')
This uses safe navigation operator on nullable return type, so it's clearer than try/catch workaround.
I'd like to use crashlytics in our app, but I'm not allowed to upload it's proguard mapping file anywhere to the outside world (company policy). Is it possible to use Crashlytics but with obfuscated stacktraces?
In io.fabric plugin's docs I've found this option:
ext.enableCrashlytics = false
But it disables whole reporting, so that's not what I want.
I have added this at the end of app gradle file:
tasks.whenTaskAdded {task ->
if(task.name.toLowerCase().contains("crashlytics")) {
task.enabled = false
}
}
Build log:
> Task :app:crashlyticsStoreDeobsDebug SKIPPED
> Task :app:crashlyticsUploadDeobsDebug SKIPPED
Please note that this disables all crashlytics related tasks. Uploading proguard mapping file by default is some kind of misunderstanding. It is like uploading private key and its password. This file should only be stored in your vault. So I guess it is better to completely disable all their task by default :)
I am just wondering why this is not a big issue for developers.
They have everything planned ! ;-) According to this link : "Crashlytics automatically de-obfuscates stack traces for your reports", so you shouldn't have to worry about it.
Simply obfuscate your app with ProGuard, don't forget to update ProGuard rules to avoid unexpected crashes with release app, and it should be ok !
(help page is about Eclipse, but I used Crashlytics with Android Studio just some days ago, and it works fine too)
EDIT 1 : and according to the very end of this second link, Crashlytics automatically upload mapping file during build. It seems you aren't able to disable this.
EDIT 2 : maybe if you use Ant, you would be able to customize (at least a bit) build rules, thanks to crashlytics_build.xml and crashlytics_build_base.xml files. But I'm not used to Ant, and even there, when I read file, it seems the "mapping files auto upload" can't be disabled. :-/
try disable task 'crashlyticsUploadDeobs':
afterEvaluate {
for (Task task : project.tasks.matching { it.name.startsWith('crashlyticsUploadDeobs') }) {
task.enabled = false
}}
Add to app build Gradle file
firebaseCrashlytics {
mappingFileUploadEnabled false
}
https://firebase.google.com/docs/crashlytics/get-deobfuscated-reports?platform=android
if you does not have internet connect at that time what will happened mapping will upload to crashlytics or not.
I am having trouble building apk in release mode. No matter what I do I always get BuildConfig.DEBUG flag set to true.
I tried the following
set android:debuggable="false" in manifest file.
Used Export option(by right clicking on project in eclipse) to create signed apk.
Use Android Tools->Export unsigned apk to create apk.
But when I decompiled the code using dex2jar and JD I saw BuildConfig.DEBUG set to true.
Also, when I used the following code in app to check debug flag, I always get result 'true'(in both debug and release mode)
Toast t=Toast.makeText(this, String.valueOf(BuildConfig.DEBUG), Toast.LENGTH_LONG);
t.show();
Please tell me the correct method to build the apk in release mode and to protect code from decompiling.
Please help me.
It has been a bug with ADT, which I am still able to reproduce
https://code.google.com/p/android/issues/detail?id=27940
As a workaround you may use your own boolean to toggle (true/false) logging as this:
public final class AppConfig {
public static final boolean DEBUG = false;
}
// and later use it as
if (AppConfig.DEBUG) {
Log.d(TAG, "lorem ipsum..");
}
In the newest version of ADT (r17) a generated constant was added BuildConfig.DEBUG that is set according to the build type. The problem I have is that it is never set to false, I expected it to change when doing "Android Tools -> Export Signed Application Package" but it hasn't for me.
So how do I change the build type?
Added a feature that allows you to run some code only in debug mode.
Builds now generate a class called BuildConfig containing a DEBUG
constant that is automatically set according to your build type. You
can check the (BuildConfig.DEBUG) constant in your code to run
debug-only functions
Currently you can get the correct behavior by disabling "Build Automatically", cleaning the project and then export via "Android Tools -> Export Signed Application Package". When you run the application BuildConfig.DEBUG should be false.
With Eclipse, I always disable "Build Automatically" option before Exporting the app in release. Then I clean the project and export. Otherwise it starts compiling in debug mode, and then the value of BuildConfig.DEBUG may be wrong.
With Android Studio, I simply add my own custom variable in the build.gradle:
buildTypes {
debug {
buildConfigField "Boolean", "DEBUG_MODE", "true"
}
release {
buildConfigField "Boolean", "DEBUG_MODE", "false"
}
}
When I build the project, the BuildConfig.java is generated as follows:
public final class BuildConfig {
// Fields from build type: debug
public static final Boolean DEBUG_MODE = true;
}
Then in my code I can use:
if (BuildConfig.DEBUG_MODE) {
// do something
}
I recommand to clean after switching debug/release build.
It doesn't work properly:
Issue 27940: BuildConfig.DEBUG is "true" for exported application package
It's disappointing that they sometimes release buggy features.
Check for imports, sometimes BuildConfig is imported from any class of library unintentionally. For example:
import io.fabric.sdk.android.BuildConfig;
In this case BuildConfig.DEBUG will always return false;
import com.yourpackagename.BuildConfig;
In this case BuildConfig.DEBUG will return your real build variant.
p.s I just copy this one from my answer here:BuildConfig.DEBUG always false when building library projects with gradle
It does work, but note that the code file never changes, even when exporting the signed file. The export process changes the value of this variable to false, which might give you the false impression that it is not working.
I tested this with logging statements like
if (com.mypackage.BuildConfig.DEBUG)
Log.d(TAG, location.getProvider() + " location changed");
When testing, my Log statements no longer produce any output.
From Preparing for Release:
Turn off logging and debugging
Make sure you deactivate logging and disable the debugging option
before you build your application for release. You can deactivate
logging by removing calls to Log methods in your source files. You can
disable debugging by removing the android:debuggable attribute from
the tag in your manifest file, or by setting the
android:debuggable attribute to false in your manifest file. Also,
remove any log files or static test files that were created in your
project.
Also, you should remove all Debug tracing calls that you added to your
code, such as startMethodTracing() and stopMethodTracing() method
calls.
More information is following the link.
The solution for me:
Project -> Build Automatically
Project -> Clean
Project -> Build
Project Export Android application
It's work in r20
I would want to propose a simple workaround if you use proguard during APK export.
Proguard provides a way to remove calls to specific functions in release mode. Any calls for debugging logs can be removed with following setting in proguard-project.txt.
# Remove debug logs
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
}
And optimization setting in project.properties.
proguard.config=${sdk.dir}/tools/proguard/proguard-android-optimize.txt:proguard-project.txt
With this, you don't need to concern any unnecessary String computation passing to debug log to which #Jeremyfa pointed. The computations are just removed in release build.
So the workaround for BuildConfig.DEBUG uses the same feature of proguard like following.
public class DebugConfig {
private static boolean debug = false;
static {
setDebug(); // This line will be removed by proguard in release.
}
private static void setDebug() {
debug = true;
}
public static boolean isDebug() {
return debug;
}
}
And following setting in proguard-project.txt.
-assumenosideeffects class com.neofect.rapael.client.DebugConfig {
private static *** setDebug();
}
I would prefer using this to disabling the Build Automatically option, because this doesn't depend on the builder's individual IDE setting but is maintained as committed file which are shared among developers.
Does not work properly as far as I understood (Android issue 22241)
I had some trouble on a project (working with Eclipse), that constant was not set to true when exporting a signed APK of my project :(
Would love to hear it works though
a good way is creating your own class :
public class Log {
public static void d(String message) {
if (BuildConfig.DEBUG)
android.util.Log.d(
"[" + (new Exception().getStackTrace()[1].getClassName()) + "]",
"{" + (new Exception().getStackTrace()[1].getMethodName()) + "} "
+ message
);
}
}
will you check your app level build.gradle debuggable true for release build
buildTypes {
release {
debuggable true
}
}
instead you keep false or comment that line
buildTypes {
release {
//debuggable true
}
}
now you will get BuildConfig.DEBUG false for release build
I've seen some strange behavior that has to do with when the values in BuildConfig are set to their final values. This may have something to do with your issue.
The simple explanation is that default values are set initially before Proguard is run, then after Proguard runs, the BuildConfig file is regenerated with the proper values. However, Proguard has already optimized your code by this point and you have issues.
Here is a bug I created against Gradle. https://code.google.com/p/android/issues/detail?id=182449