android project with files in assets, these file need encrypt before generator apk
every times i changed some file in assets,
i need copy out these file , encrypt ,then copy into assets
what i want is:
keep file in assets not encypt (can edit it conveniently) ,
but file in .apk encrypted
encrypt work do automatically by gradle.build
my basic idea is thad add some task before mergeDebugAssets (or mergeReleaseAssets)
before mergeDebugAssets, i replace all file in file://$MODULE_DIR$/build/assets
code like below
task processAssetFile {
// code : replace file in build/assets
}
mergeDebugAssets.dependsOn processAssetFile
the problem is
mergeDebugAssets is not available in gradle.build
error log below:
Could not find property 'mergeDebugAssets' on project ':gradle'.
so is there some idea can achieve my goals ?
android studio ver :0.52
You can always find the task by its name.
I would also suggest that you want to perform encryption for other build variants (makes sense for release even more than for debug).
This requires a little bit of coding since you need to create a task for each variant, too.
It is best to create those tasks dynamically so you don't forget a variant.
Say you're encrypting with some command-line tool, the code you need to add could look like this:
android.applicationVariants.all { variant ->
String suffix = variant.variantData.name.capitalize()
Task mergeAssetsTask = tasks.findByName("merge${suffix}Assets")
Task processAssetFileTask = tasks.create(name: "process${suffix}AssetFile", type: Exec)
processAssetFileTask.commandLine "path/to/your/encryption/tool",
"--input-file=${inputFilePath}",
"--output-file=${outputFilePath}"
mergeAssetsTask.dependsOn processAssetFileTask
}
Related
I working an Android application. Some activities, I used webview and load html from Android asesst folder. On apk if rename package to name.apk.zip then anyone can easily access my asesst folder content.
Now I want to protect my assect content mainly html files.
Please help to give some suggest about html encryption or Android studio plugins about protection.
Most efficient way to do this, it's include that files in your Server, and getting files by authorization.
To do it locally. I suggest to create custom task in gradle for mapping your html/css files in some incode storage, with Base64 (encoding just for ex.). It's looks like:
task mapAssets(dependsOn: build) {
SOURCE_FILE = 'Path to Source File'
doFirst {
println "I'm Gradle"
}
String source = new File(SOURCE_FILE).text
ENCODED_FILE = 'Path to Encoded File'
new File(ENCODED_FILE).withWriter { out ->
out.println source.bytes.encodeBase64().toString()
}
}
Later in your Java code, just find ENCODED_FILE and make call with reading file and mapping again in HTML, from Base64 (or any other encoding).
I created Sample data directory for my Android app using the process described in this article. I would like to share this set of sample data between my projects, so I created a library that only has sample data inside. But as far as I can see sampledata folder is not being compiled into the library. Is there a way to share sample data between multiple Android projects?
As already said, you can't do that with a library because sampledata simply can't be part of an Android library.
One thing you could though, host your names file somewhere and then fetch it with a gradle task, you could just add to an app's build.gradle
clean.doFirst {
println "cleanSamples"
def samplesDir = new File(projectDir.absolutePath, "sampledata")
if (samplesDir.exists()) {
samplesDir.deleteDir()
}
}
task fetchSamples {
println "fetchSamples"
def samplesDir = new File(projectDir.absolutePath, "sampledata")
if (samplesDir.exists()) {
println "samples dir already exists"
return
}
samplesDir.mkdir()
def names = new File(samplesDir, "names")
new URL('http://path/to/names').withInputStream { i ->
names.withOutputStream {
it << i
}
}
}
You can see 2 functions there, the first one is run before a clean task and it will just delete your sampledata folder. The second one is a task run on every build, it won't download the file every time but only if the directory is not there.
I understand you might as well copy paste names file, but, with this method you need to copy paste the tasks only once and you would be able to change names in any project just by uploading a new file and doing a clean build.
The short answer is no, you can't do that with sampledata folder. Basically, the format of the Android Libraries is AAR. If you reference the official documentation, it says that:
The file itself is a zip file containing the following mandatory entries:
/AndroidManifest.xml
/classes.jar
/res/
/R.txt
/public.txt
Additionally, an AAR file may include one or more of the following optional entries:
/assets/
/libs/name.jar
/jni/abi_name/name.so (where abi_name is one of the Android supported ABIs)
/proguard.txt
/lint.jar
So, sampledata can't be a part of AAR library.
UPDATE
Instead of your own data samples, you can use predefined sample resources. For example #tools:sample/first_names will randomly select from some common first names, eg., Sophia, Jacob, Ivan.
Example of usage:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="#tools:sample/first_names" />
I want to use open alpr (automatic licences plate recognition) library in my android project. I compiled everything successfully and now it is time to use open alpr in app but...
to create Alpr class object properly I have to provide path to config file and path to runtime_data folder which contains some mandatory files needed by open alpr (ocr and trained data).
I tried something like:
Alpr alpr = new Alpr("eu", "android_assets/alpr.conf", "android_assets/runtime_data");
but Alpr.isLoaded() returns false which means that config or runtime_data have not been found.
Path to assets folder in project is: src/main/assets.
Can someone explain to me how path to "runtime_data" directory and "alpr.conf"
should looks to be visible by open alpr?
Thanks in advance.
I am not familiar with the specific library, but on newer Android devices (Android 6 and up), you can not rely on your application files residing under /data/data/your.package.name
The actual library name still includes the package name of your app, but also has some identifier appended to it in base64 format.
This identifier is unique per installation, and it will change if you uninstall and reinstall the app on the same device.
So, if your library needs to use a configuration file with a path to some other files, there are 2 options:
The right way:
Get the real address of your application files folder using Context.getFilesDir().
Unpack you files from the assets folder of the APK on the device using AssetManager.
Programmatically rewrite your configuration file with the path returned by getFilesDir().
The "hacky" but simpler way:
Use public storage to unpack your files.
You will need to add WRITE_EXTERNAL_STORAGE permission to your app, and unpack the assets files to the external storage.
For backwards compatibility this will be available under /sdcard folder on most Android devices, even with the latest Android version.
The second method is not recommended since using /sdcard directly is deprecated and strongly discouraged by Google.
Also, not all Android devices have /sdcard link to their public storage, but this is the only way to avoid dynamically editing the configuration file after installation.
Important note before you start implementing those steps. This library supports only arm CPU architecture. Good news is, most probably, your physical device is using arm architecture but to make sure just double-check it before implemting those steps.
I've recompiled this library to a new wrapper library. In original library, you need to manually configure openalpr.conf file and edit its content with correct path to your data directory. Manual configuration is cumbersome because since Android 5 multiple user accounts is supported and we can't simply hardcode data directory as /data/data/com.your.packagename/..... Because every user gets their symlink to data directory as /data/user/0/com.your.packagename/..... All those manual steps are gone in recompiled wrapper library.
Implementation
Add this in your root build.gradle at the end of repositories:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
Add the dependency into app module:
dependencies {
...
implementation 'com.github.mecoFarid:openalpr:1.0.0'
}
And you're done. Please check this sample app to get started with UI.
Troubleshooting:
If your target sdk is targetSdkVersion >= 24 and you're running your app on a device with Android API 24+ you'll get following error:
android.os.FileUriExposedException: file:///storage/emulated/0/OpenALPR/2019-09-21-01-32-13.jpg exposed beyond app through ClipData.Item.getUri()
To solve this error: you can add following lines into onCreate() of your Activity as a workaround or you may use this thread for offical solution:
if(Build.VERSION.SDK_INT>=24){
try{
Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
m.invoke(null);
}catch(Exception e){
e.printStackTrace();
}
}
TEST:
You can use this image to test your app.
"/data/data/yourpackagename" + File.separatorChar + "runtime_data"
+ File.separatorChar + "openalpr.conf";
I have a Parse account that I'm using to store user data for my Android application. Because I'm using source control, I don't want to leave my secret key embedded in the code. Is there a way to have a "config" file that I would keep out of source control, that can then host the key? If that's not feasible, what are the best practices of handling such a situation?
Yes, you can create a folder outside of source control, put a file called app.properties in there, put your key in that properties file and add the folder to your build path. Then use a properties loader to load it from the classpath.
If you have many developers or more than one dev machine, you can set the local properties location as a variable in your build path so that each developer can configure their own.
One option is to put the key in an environment variable and then read it during your build.
in your pom.xml declare a property (secret.key)
<properties>
<secretKey>${env.SECRET_KEY}</secretKey>
<properties>
further down enable "filtering" on your resources
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
In resources maintain a "config.properties" to read with the variable ready for substitution:
secret_key=${secretKey}
Filtering in maven will replace ${secret.key} with the value from your environment variable.
If you are using gradle for your build with Android studio see section 16.6.6.2 on filtering files.
Within build.gradle add the following
import org.apache.tools.ant.filters.FixCrLfFilter
import org.apache.tools.ant.filters.ReplaceTokens
task copyProductionConfig(type: Copy) {
from 'source'
include 'config.properties'
into 'build/targetpath/config'
expand([
secretKey: System.getenv("SECRET_KEY")
])
}
In gradle you can also request input when you run gradlew using
Console console = System.console()
def password = console.readPassword("Enter Secret Key: ")
And then apply it to the appropriate config or source files.
My android app does some http requests to my server. However sometimes I am debugging the new api code that runs on my development machine. I would like to be able to pass something (like an environment variable) so in my code, if it's present I would be able to use that as the hostname for the api requests from the android emulator.
So I'm looking for a way to pass something like:
API_SERVER=http://10.0.2.2/myapp/
and in my code I would use it somehow, for example:
final static String API_SERVER_REAL = "http://example.com/";
final String apiServerOverride = System.getenv("API_SERVER");
final String API_SERVER = (null != apiServerOverride && !apiServerOverride.isEmpty() ? apiServerOverride : API_SERVER_REAL);
I know this thread is quite old, but in my opinion none of provided answers actually solves the problem. Flavors are ill-suited for parametrizing your build with things like API URLs, and even worse for things like API keys etc.
Firstly, build.gradle which defines flavors is part of project source, therefore it must not contain such information in order to be safely committed into source control systems.
Secondly, a need may arise to test different flavors against different API endpoints/keys. What if you just want to hit some debug http server you just created to solve a bug? Would you create a flavor for that? Probably not... Flavors are good for things like "free flavor" and "premium flavor".
This problem is easily solved using gradles -P flag. You can access gradle properties that are passed this way as regular variables inside your gradle.build, and you can vary it's behavior accordingly.
If you want to push this flags further into your application you can use Scott's solution that was posted here, combined with the provided flag.
The build command would then probably look like:
$ gradle build -Papiroot=http://www.example.com
And in your build.gradle you would define the writeValue task like this:
task writeValue(type:Exec) {
commandLine '/usr/local/bin/adb', 'shell', "echo 'API_SERVER=${apiroot}' > /data/data/values.properties"
}
FYI the -P flag can be easily configured in Android Studio by navigating from the menu:
Run -> Run/Debug Configurations -> Defaults -> Gradle -> Script Parameters
Probably the simplest thing is to write the data you want to pass to a file on the device in /data/data; your Android app can read the device trivially (perhaps make it a .properties file and use java.util.Properties to read it in). To write it out, use this kind of task in your build.gradle file (and use the correct path to the adb command for your setup):
task writeValue(type:Exec) {
commandLine '/usr/local/bin/adb', 'shell', 'echo \'API_SERVER=http://10.0.2.2/myapp/\' > /data/data/values.properties'
}
There's documentation on Gradle exec tasks at http://www.gradle.org/docs/current/dsl/org.gradle.api.tasks.Exec.html
You can execute this task manually from Android Studio by using the Gradle tasks view:
Due to a bug in Android Studio, you cannot pass vm or script parameters from a gradle configuration. The issue is here.
As a workaround in Linux envs (probably Mac too), you can create a bash configuration where you will be able to add all desired parameters.
I suggest using productFlavors. Each flavor can contain environment specific settings. I simply have a class called 'Environment' which contains all the public static final Strings that I need and each product flavor includes an different version of this class with the values set for the environment.