How to assign API key in manifest from Constant Value class? - java

I am trying to assign value to below meta in manifest.
currently i have assign value from string.xml class.
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value= "#string/MAPS_API_KEY" />
But I want Some thing like this..
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value= com.packagename.MyConstantInterface.MAPS_API_KEY />
I have search a lot, but haven't find a good solution.
NOTE: I am getting all APIs keys from server, storing keys in snappy db and then assigning keys from snappy db to MyConstantInterface.

STEP 1: Create a file named secrets.properties in the main folder (i.e below local.properties, app, build, gradle, README.md,etc.
STEP 2: Paste your API Key in secrets.properties (i.e GOOGLE_API_KEY, FACEBOOK_APP_ID, etc)
STEP 3: Sync the project or Rebuild.
STEP 4: Open build.gradle (app) and create a def function to access the key declared in the secrets.properties.
def getApiKey(){
def Properties props = new Properties()
props.load(new FileInputStream(new File('secrets.properties')))
return props['GOOGLE_MAPS_API_KEY']
}
STEP 5: Create a variable for the function getApiKey() in defaultConfig using manifestPlaceholders to use it in AndroidManifest.xml
defaultConfig {
defaultPublishConfig 'debug'
applicationId "YOUR_APPLICATION_ID"
minSdkVersion 19
targetSdkVersion 27
versionCode 1000
versionName '0.1.0'
manifestPlaceholders = [ GOOGLE_MAPS_API_KEY:getApiKey()]
}
You’re good to go. Now GOOGLE_MAPS_API_KEY variable is public and can be used in AndroidManifest.xml like below
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${GOOGLE_MAPS_API_KEY}" />
manifestPlaceholders — It helps to create a global variable that can be used only in AndroidManifest.xml
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt')
, 'proguard-rules.pro'
}
applicationVariants.all { variant ->
variant.buildConfigField "String", "GOOGLE_MAPS_API_KEY"
, "\""+getApiKey()+"\""
}
}
And, you can use GOOGLE_MAPS_API_KEY in Java or Kotlin classes like
BuildConfig.GOOGLE_MAPS_API_KEY
Finally, don’t forget to add secrets.properties to your .gitignore file.
Solution was gotten from This Medium post by Chandrasekar Kappusamy

You simply can not simply use a java variable.
Instead of it, You need to inject build variables into the manifest
Declaration:
defaultConfig {
...
manifestPlaceholders = [MAPS_API_KEY_FOR_MANIFEST: "your_maps_key_here"] // TO use in manifest file
buildConfigField "String", "MAPS_API_KEY", '"your_maps_key_here"' // TO use in java file
}
Use in AndroidManifest.xml:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value= "${MAPS_API_KEY_FOR_MANIFEST}" />
Java file Usage:
BuildConfig.MAPS_API_KEY
For more information, You can have a look at this and this.

Related

Build Multiple apk from 1 project, for upload in playstore

I am working on a app for school in android studio using java
I want to generate multiple apk for school with their school name and logo, (about 50+ schools)
Is there any way to save time generating one by one
in future need to update all
Read official guideline about productFlavors.
Creating product flavors is similar to creating build types: add them
to the productFlavors block in your build configuration and include
the settings you want. The product flavors support the same properties
as defaultConfig—this is because defaultConfig actually belongs to the
ProductFlavor class.
productFlavors {
elvispresley {
applicationId 'your_package_id'
versionCode 1
versionName '1.0'
}
whitneyhouston {
applicationId 'your_package_id_2'
versionCode 2
versionName '2.0.1'
}
projectOne {
applicationIdSuffix ".one"
}
projectTwo {
applicationIdSuffix ".two"
}
}

Changing to two environment using one APK

we are developing android app and there are two different environment that we need to point separately. lets say it staging and production but due to compliance requirement we need to provide one apk file and there should be a way to change environment
when its required so that they can make sure that same file go production that they tested on staging.
We are keeping url details in string.xml and normally we give two apks pointing to two diferent environment.
so we are just wandering is there any tool or any other method that we can change string.xml values inside apk. So that they can use that tool to
change url when they required.
Use this kind of way to separate the urls,
buildTypes {
debug {
buildConfigField "Boolean", "IS_DEBUG", 'true'
buildConfigField "String", "URL", 'https://appsgit.com/debugurl'
}
release {
buildConfigField "Boolean", "IS_DEBUG", 'false'
buildConfigField "String", "URL", 'https://appsgit.com/releaseurl'
}
}
Please check this blog post for more info..
If this solution doesn't work. You can try Gradle BuildFlavor.
Add ProductFlavor like below (Free & Paid).
productFlavors {
free {
applicationId "com.appsgit.freeapp"
buildConfigField 'boolean', 'IS_PAID', 'false'
buildConfigField 'boolean', 'URL', 'http://freeversion.com'
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = new File(output.outputFile.parent, output.outputFile.name.replace("app-release.apk", "app-free-" + defaultConfig.versionName + ".apk"))
}
}
}
paid {
applicationId "com.appsgit.paidapp"
buildConfigField 'boolean', 'IS_PAID', 'true'
buildConfigField 'boolean', 'URL', 'https://paidversion.com'
versionCode 1
versionName "1.0"
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = new File(output.outputFile.parent, output.outputFile.name.replace("app-release.apk", "app-paid-" + defaultConfig.versionName + ".apk"))
}
}
}
}
And create code base like here,
Don't forget Main is shared to all the flavors.
Since strings.xml in your apk will be changed so it will be two different apk for staging and production (different sha256 sum).
If it is not a problem then you can use "flavor" for two different environments.
https://developer.android.com/studio/build/build-variants.html#flavor-dimensions
If it is necessary to have only one apk for staging and production then you can add some kind of killswitch. For example it may be a file with special name. If the file is exist on device then apk use staging path in other way apk use production way.
Hope it will be helpful for you.
You should let the user choose the environment at runtime.
For that, you should read the environment option from the shared preferences.
The easiest way would be to create a Preferences Activity which would have a checkbox to select whether use production or staging environment. Then, map the logic to use the appropriate base URL for when the checkbox is checked or not.

Android System.loadLibrary crashing

I'm trying to include a c file, ImageProc into my java file to use it's functions.
I got the code from a MjpegInputStream file (where everything is supposed to work, but of course its never that easy)
Here is the code that crashes (somehow the catch isn't catching it)
static {
try {
System.loadLibrary("ImageProc");
}
catch (Exception e){
e.getMessage();
}
}
The makefile is:
include $(CLEAR_VARS)
LOCAL_MODULE := ImageProc
LOCAL_SRC_FILES := ImageProc.c
LOCAL_LDLIBS := -llog -ljnigraphics
LOCAL_SHARED_LIBRARIES := prebuilt-libjpeg
LOCAL_C_INCLUDES := external/include jni/external/include
So to my understanding I should just be able to use ImageProc.
I know it went through and compiled the c file because at first it couldn't find the h file references (fixed now).
One other thing i'm not sure about is that I call the function pixeltobmp which in the c file is defined as Java_com_camera_simplemjpeg_MjpegInputStream_pixeltobmp which strikes me as odd. I tried changing the name of the method to include the package i'm using rather than the one I copied it from, but that didn't fix anything.
Any help is appreciated.
Additional info: I'm using gradle build 2.10
1. Compile your library
2. Check if you have the .so compiled library(this is important!)
3. In your gradle file add this:
android {
compileSdkVersion 23
buildToolsVersion "22.0.1"
defaultConfig {
minSdkVersion 18
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
sourceSets.main {
jni.srcDirs = []
File configFile = file('pathToYourLibsFolder')
jniLibs.srcDir configFile.absolutePath
}
Then it should work.
In build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
...
}
buildTypes {
...
}
ndk {
moduleName "ImageProc"
// stl "stlport_static"
// ldLibs "log"
}
}
}
As an alternative option, the code that you're using can be easily modified to remove the dependency on OpenCV (or it can now 2 years after you asked the question).
MjpegInputStream.java has two relevant methods, readMjpegFrame() and readMjpegFrame(Bitmap bmp).
Only the later relies on OpenCV and therefore the native library dependency. If you modify the code to remove this method, and then remove:
static {
System.loadLibrary("ImageProc");
}
public native int pixeltobmp(byte[] jp, int l, Bitmap bmp);
public native void freeCameraMemory();
You will no longer have this problem and can still use readMjpegFrame() to get the content you want.
Whether this is less performant, I'm not certain, but it's working fine in my use case.

How to read value from gradle.properties in java module?

I have a project in Android Studio with a couple of modules.
The app module. With apply plugin: 'com.android.application'.
The androidLibrary module. With apply plugin: 'com.android.library'.
The javaLibrary module. With apply plugin: 'java'.
I want to declare some variables in the project gradle.properties file and be able to read them from the javaLibrary module.
I have declared the properties in the following ways according this documentation...
mysuperhost=superhost
systemProp.mysuperhost=superhost
ORG_GRADLE_PROJECT_mysuperhost=superhost
org.gradle.project.mysuperhost=superhost
... and tried to read them this way with no success:
System.getenv("mysuperhost");
System.getProperty("mysuperhost");
I know how to read properties from the BuildConfig class, but this is a generateed class in the app module (with apply plugin: 'com.android.application'), so this does not work for this particular case.
If you have some value inside of the your gradle.properties file like
mysuperhost=superhost
then write the following lines in the your build.gradle file (to grab property from gradle.properties file and add it into BuildConfig.java class):
// ...
// ...
android {
// Just for example
compileSdkVersion 23
// Just for example
buildToolsVersion "23.0.2"
// ...
// ...
defaultConfig {
// Just for example
minSdkVersion 14
// Just for example
targetSdkVersion 23
// This is the main idea
buildConfigField('String', 'MY_SUPER_HOST', "\"${mysuperhost}\"")
// ...
// ...
}
// ...
// ...
}
// ...
// ...
After that build your project and you are able to use your value via BuildConfig.MY_SUPER_HOST
Your statement about being unable to use BuildConfig is not entirely accurate, as you can use Java reflection to find the public static members of BuildConfig as long as you know its fully qualified package.
Say the full package name of your generated BuildConfig is com.company.app.BuildConfig. You can get its Class object with:
Class<?> klass = Class.forName("com.company.app.BuildConfig");
Then you can use that Class object to pick out the fields of it by name:
Field field = klass.getDeclaredField("BUILD_TYPE");
Then you can get its value:
String value = field.get(null);

Gradle DSL method not found: storeFile()

I'm using Android Studio 1.1.0. When I try to sync my Gradle file, I get the following error:
Gradle DSL method not found:storeFile()
Here is my gradle configuration:
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
applicationId "skripsi.ubm.studenttracking"
minSdkVersion 16
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
signingConfigs {
release {
storeFile (project.property("Students_tracking_keystore.jks") + ".keystore")
storePassword "####"
keyAlias "####"
keyPassword "#####"
}
}
}
Can anyone help?
A couple of things to note:
The storeFile DSL method has the following signature:
public DefaultSigningConfig setStoreFile(File storeFile)
i.e. it expects a File to be passed in. You probably need to place a File constructor in your code to ensure you are actually creating a File object. Because you're currently not passing in a file, Gradle is complaining that it can't find a method with the appropriate signature.
Secondly, you are currently appending two suffices to the filename: .jks and .keystore. You should only include one of these based on the suffix of the file you are referencing (it's probably .jks, but you should check to be sure).
In short, one of the following replacement lines will probably work for you:
storeFile file(project.property("Students_tracking_keystore") + ".keystore")
or
storeFile file(project.property("Students_tracking_keystore") + ".jks")
or
storeFile file(project.property("Students_tracking_keystore.keystore"))
or
storeFile file(project.property("Students_tracking_keystore.jks"))

Categories

Resources