Showing posts with label apk. Show all posts
Showing posts with label apk. Show all posts

Thursday, October 4, 2018

How to sign android app with platform keys using gradle?

Leave a Comment

I saw couple similar questions like:

but I feel my problem is different.

First of all I use:

android:sharedUserId="android.uid.system"

so I need to sign my app with platform key. I'm able to do that in this way:

cd $ANDROID_ROOT/out/host/linux-x86/framework java -Djava.library.path=$ANDROID_ROOT/out/host/linux-x86/lib64 -jar signapk.jar $ANDROID_ROOT/build/target/product/security/platform.x509.pem $ANDROID_ROOT/build/target/product/security/platform.pk8 $APP_DIR/app/build/outputs/apk/debug/app-debug.apk $APP_DIR/MyApp-signed.apk 

However I want to do signing from gradle, so I have generated jks file in this way:

./keytool-importkeypair -k my_keystore.jks -p my_password -pk8 $ANDROID_ROOT/build/target/product/security/platform.pk8 -cert $ANDROID_ROOT/build/target/product/security/platform.x509.pem -alias platform 

and I've modified app/build.gradle to have:

 signingConfigs {      release {          storeFile file("my_keystore.jks")          storePassword "my_password"          keyAlias "platform"          keyPassword "my_password"      }  }   buildTypes {      release {          minifyEnabled false          proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'           signingConfig signingConfigs.release      }  } 

I've checked that my_keystore.jks has platform alias with:

keytool -list -v -keystore my_keystore.jks | grep Alias Alias name: platform 

but when I try to do:

./gradlew assembleRelease 

or:

./gradlew signingReport 

I get:

Failed to read key platform from store "(...)/my_keystore.jks": Invalid keystore format

Update: I've tried following dr_g tips and I'm able to sign app using Android Studio (Build -> Generate Signed APK), so I guess keystore is ok, but still I get the same error when using assembleRelease. I've also tried generating my own keystore as suggested by deadfish and indeed keystore generated by Android Studio is fine for gradle and assembleRelease works, but it's not platform key, so I can't use it unfortunately.

3 Answers

Answers 1

Please try using the .keystore variant. There could be ways to fix the java keystore (.jks) format but it is likely to take more time.

1) Generate your .keystore file from your separate key files

$ openssl pkcs8 -inform DER -nocrypt -in \   $ANDROID_ROOT/build/target/product/security/platform.pk8 -out platform.key $ openssl pkcs12 -export -in \   $ANDROID_ROOT/build/target/product/security/platform.x509.pem -inkey \   platform.key -name platform -out platform.pem -password pass:password $ keytool -importkeystore -destkeystore platform.keystore -deststorepass \   password -srckeystore platform.pem -srcstoretype PKCS12 -srcstorepass    password 

2) Test your new keystore:

$ jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore \   platform.keystore -storepass password your-app.apk platform 

3) Deploy keystore in your gradle build:

signingConfigs {  debug {     storeFile     file('debug.keystore')     storePassword 'android'     keyAlias      'androiddebugkey'     keyPassword   'android'  }  release {     storeFile     file('platform.keystore')     storePassword 'password'     keyAlias      'platform'     keyPassword   'password'  }  } 

The above build.gradle is also showing an example of using the android debug keystore as standard for debug builds.

Answers 2

use the .keystore file not the .jks when you generate you app,Android studio will notice you create a keyStore, try this key.

Answers 3

After chat with deadfish and following his suggestions (thanks for help!) I've come up with following workaround in app/build.gradle (inside android {}):

applicationVariants.all { variant ->     variant.assemble.doLast {         exec {             commandLine 'sh', '../mySigningScript.sh'         }     } } 

This will run my script everytime when assembleDebug or assembleRelease is finished. I will not accept my answer because it's not answering my question and it forces me to remove signingConfigs from gradle but at least it's a workaround which potentially could be used if no better solution is proposed.

Read More

Wednesday, September 19, 2018

Generate APK for different architectures - FFmpegMediaMetadataRetriever

Leave a Comment

PLEASE SEE EDIT 1


I'm busy adding FFmpegMediaMetadataRetriever pre-build .aar files to my project to reduce the Apk file size for each architecture.

This post added the following to his Gradle:

android { splits {         // Configures multiple APKs based on ABI.         abi {             // Enables building multiple APKs per ABI.             enable true              // By default all ABIs are included, so use reset() and include to specify that we only             // want APKs for x86, armeabi-v7a, and mips.             reset()              // Specifies a list of ABIs that Gradle should create APKs for.             include "x86", "x86_64", "armeabi-v7a", "arm64-v8a"              // Specifies that we want to also generate a universal APK that includes all ABIs.             universalApk false         }     }     //...     } 

The FFmpegMediaMetadataRetriever library provide the following .aar files:

image


My Questions:

  • Should I place the .aar files in my libs folder as it is (without creating folders for each architecture), or should I add it in a folder?
  • Which of the above .aar files should I use to support all architectures?
  • In the post he also talks about versioning, is this necessary (my application is live and I don't want to mess up the versioning - my current version is 21)?

He implemented versioning like this:

// Map for the version code that gives each ABI a value. def abiCodes = ['x86':1, 'x86_64':2, 'armeabi-v7a':3, 'arm64-v8a':4]  // APKs for the same app that all have the same version information. android.applicationVariants.all { variant ->     // Assigns a different version code for each output APK.     variant.outputs.each {         output ->             def abiName = output.getFilter(OutputFile.ABI)             output.versionCodeOverride = abiCodes.get(abiName, 0) * 100000 + variant.versionCode     } } 

I'm looking for someone that has perhaps used the .aar files of FFmpegMediaMetadataRetriever that can give me guidance on how to correctly implement it.


EDIT 1:

After learning more about different architectures/ABI's, I THINK it is save to say that if I only include armeabi-v7a then most devices would be "covered"? (My minimum sdk is 16).

Does that then mean that I don't have to split the APK and I don't have to worry about versioning?

I can then just import the .aar - armv7-fmmr.aar as normal?

1 Answers

Answers 1

First of all, you shouldn't take for granted, that armeabi-v7a will get you "covered". As per this blog post:

In August 2019, Play will require that new apps and app updates with native libraries provide 64-bit versions in addition to their 32-bit versions.

Edit after I had a look at the project you're mentioning

It should be enough to use all-fmmr.aar. It contains .so files for all architectures. If you then use apk splits, each apk will only contain single architecture.

I would also consider including the library via gradle:

dependencies {     compile 'com.github.wseemann:FFmpegMediaMetadataRetriever:1.0.14' } 

Rest of the original answer is below

As per the project scrutcture, at least in our app and library, we don't have multiple .aar files. In single .aar there are multiple native libraries (.so) like this (you can open it as zip):

library.aar +-jni | +-armeabi-v7a | | \-nativeLib.so  | +-arm64-v8a | | \-nativeLib.so  | +-x86 | | \-nativeLib.so  | \-etc.  +-assets +-drawable +-res +-classes.jar \-etc. 

You do not need to have separate .aar files in order for apk splits to work. You can have single .aar with native libs for multiple architectures and you will get multiple apks each for single arch.

If you already have multiple .aar files that you want to use and each has structure like this, but with only single architecture, then you do not need to create folders by architecture to hold them. Instead you can include them and hopefully they will get merged in the apk.

You can check if it works by looking inside the apk as it is just a zip. Inside there will be lib folder with native libs:

lib +-armeabi-v7a | \-nativeLib.so \-etc. 

Without the splits you should get single apk with multiple architectures in its lib folder. With the splits, you will get multiple apks wit single architecture each.

Read More

Monday, August 13, 2018

Google play console does not reduce app download size

Leave a Comment

I'm developing an Android app using Xamarin latest version and Visual Studio latest version aiming Android SDK 8.0. The app is in Beta track (no release yet). I've been publishing updates of my app for 2 months using Google Play console, but something weird happened on my last update, because download size of my app growed from 14.16 MB to 29.80 MB and I haven't done anything different in my last update.

My app apk has always been 28 - 29 MB on disk (.apk size) and download size 14 MB aprox. In my last update I haven't done anything particulary big, just changed code logic and added 4 new resources (pngs total size: 43KB), no new dlls o references, no new componentes. If I use Android Studio apk analyzer on my last apk update, it says my download size should be 13,4 MB, but it seems that Google Play console does not want to reduce download size any more.

Android Studio shows download size should be 13,4 MB, but download size is actually 29 MB:

Pls your help. Thanks.

2 Answers

Answers 1

I updated Visual Studio from version 15.7.1 to 15.7.3

Visual Studio 15.7.1 to 15.7.3 = Xamarin.Android 8.3.0.19 to 8.3.3.2, consult releases.xamarin.com for details.

So the Mono runtime shared library got updated, thus the basically the whole apk is being downloaded again.

Answers 2

Have you tried Linking your app on release ?

Xamarin.Android applications use a linker to reduce the size of the application. The linker employes static analysis of your application to determine which assemblies are actually used, which types are actually used, and which members are actually used.

Used correctly it can cut your app size in half.

You can get more information here

enter image description here

Read More

Monday, April 16, 2018

Rg.Plugins.Popup doesn't work only in release mode (Xamarin.forms)

Leave a Comment

I am using Rg.Plugins.Popup and it's work fine in debug mode...but when I try the release mode or when I generate an apk it doesn't work. Did someone see something like that? I guess the others plugins are not there as well

-------------- Update ----------------------

now it works in release mode with no reason, I dont Know why... but in installed apk it doesnt work

enter image description here

1 Answers

Answers 1

if i use proguard with linker my app crashes. I only select the sdk and user assemblies linker option & it works fine.

Read More

Thursday, July 27, 2017

Force to use same certificate to sign different “buildTypes” that are configured for a particular “productFlavor”?

Leave a Comment

Background:

I am generating builds using build variant. Below are the configurations:

signingConfigs {     production {         storeFile file("some_path/buildsystem/keystore/some.release.keystore.jks")         storePassword "somepassword"         keyAlias "somekeyalias"         keyPassword "some"         v2SigningEnabled false     }      develop {         storeFile file(".some_path./buildsystem/keystore/someother.debug.keystore.jks")         storePassword "someother"         keyAlias "someotherkeyalias"         keyPassword "someother"         v2SigningEnabled false     } }  productFlavors {     production {         signingConfig signingConfigs.production       }      develop {         applicationIdSuffix ".develop"         signingConfig signingConfigs.develop      } }  buildTypes {     debug {         minifyEnabled false     }      release {         minifyEnabled false         proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'     } } 

Problem

As, of now for example if I talk about flavour production then productionRelease uses signingConfigs.production to sign the apk. But, productionDebug doesn't uses signingConfigs.production.

Expected output

When I generate the signed apk I want the gradle to do the following for me:

  1. developRelease and developDebug should be signed with only signingConfigs.develop

  2. productionRelease and productionDebug should be signed with only signingConfigs.production

Another question that is similar to this which led me to do the above: SHA-1 different for buildTypes (debug and release) for same productFlavors Firebase?

1 Answers

Answers 1

Remove the signingConfig signingCongigs.develop elsewhere in the code block

And add new property within the buildTypes like

  • production
  • develop

Now add signingConfig to it

Thereby your updated gradle file look like as below

signingConfigs {     production {         storeFile file("some_path/buildsystem/keystore/some.release.keystore.jks")         storePassword "somepassword"         keyAlias "somekeyalias"         keyPassword "some"         v2SigningEnabled false     }      develop {         storeFile file(".some_path./buildsystem/keystore/someother.debug.keystore.jks")         storePassword "someother"         keyAlias "someotherkeyalias"         keyPassword "someother"         v2SigningEnabled false     } } productFlavors {     production {     }      develop {         applicationIdSuffix ".develop"     } } buildTypes {     /* NOTE: the debug block is not required because it is a default  * buildType configuration; all of its settings are defined implicitly  * by Gradle behind the scenes.  */     debug {         minifyEnabled false     }      release {         minifyEnabled false         proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'         signingConfig signingConfigs.production     }      production {         minifyEnabled false         proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'         signingConfig signingConfigs.production     }      develop {         minifyEnabled false         signingConfig signingConfigs.develop     } } 

In the terminal use the below gradle commmand: gradle assembleProduction to generate build with production certificates similarly gradle assembleDevelop or you can also use gradle assemble

You cannot force gradle to choose the certificates for debug property rather you could create own buildTypes

As per documentation

Automate signing your applications. Debug build variants are, by default, signed with a debug key for installation on development devices. Declare additional signing configurations for publication to the Google Play store.

Read More

Wednesday, March 22, 2017

Manipulating the UI of existing native applications at runtime

Leave a Comment

I know this sounds "hacky" but I would like to personalize some UIs of the applications I have already installed in my Android. E.g. Using the same fonts, colors, etc. I know this sounds weird but I'm not thinking in creating an app for others but me, so it is not a problem if I have to root my phone or have it in debug mode. Any clue?

PS: I already saw some answers suggesting to decompress/compress the apk, but I don't want to modify the applications' sources, just injecting some style (as Stylish extension do it for Web applications) at runtime.

PS2: As Cordova apps are built with Web technologies, it may be possible to have a DOM to manipulate but how to do it from the outside?

Thanks in advance!

1 Answers

Answers 1

Disclaimer: since the question is very general, so is this answer.


Let's consider the example of the CyanogenMod (now retired...) Theme Engine. Here are some excerpets from an article that described how it worked (emphasis added here):

At the most basic level, themes are simply a mechanism to allow resources to be replaced at runtime ... just think of them as the elements which make up the application’s UI. Whenever an application is started, Android loads up the resources associated with that app and the application makes requests for these resources.

Normally...

That’s the normal flow of retrieving resources, but what happens when a theme is applied? When the system loads the resources for the application, it checks if there is a theme applied and if there is, it adds the themed resources to the original resources. This is the point at which the magic happens. When the app requests a resource, the system will check if there is a themed version of it and if so, returns the themed resource, and if not it simply returns the original. The key point here is the original resources are never modified/moved/altered, the system simply returns a resource from the theme instead of the original. As you can see in the diagram below, there is no difference as far as the application is concerned.

With a Theme present

This is done by leveraging a framework known as Runtime Resource Overlays, which was contributed to AOSP by Sony in 2014. Part of the RRO framework is a tool called IDMAP. IDMAP inspects the resources in an application and compares the resource types and names to those in the themed resources. For those resources that match it stores a mapping of the original resource to the matching resource in the theme. Once this process is complete we are left with an efficient way to determine if a resource is themed and where that resource resides.

... and it goes on some more.

A more recent tool that does this is called Substratum1, 2.

I think these should get you on the right path.

Read More

Sunday, June 26, 2016

Android signature verification

Leave a Comment

I have got lot of doubts to be cleared in the case of Android signature verification and its vulnerability.

Once we generate apk for an application we can unpack the apk and edit resource files using apktool. As we repack the edited apk back it loses its signature. I can resign the unsigned apk using the jarsigner with my own private key that i used while generating the apk. I found an application named zipsigner in playstore which can be used to sign such kind of unsigned apk.

So when this zipsigner signs the unsigned apk, whether the apk is signed with my same private key or with a different key? Because my META-INF folder still holds the XXX.SF and XXX.RSA files which holds the information of my private key. If it is with my same private key then the new apk will be an upgrade for my application or if it is a different key i will be having two different applications with same name.

From the above situations there are possibilities that malware could be included in my apk while repacking. There seems to be a loophole in Android's signature verification mechanism where the message digest of the files inside the META-INF folder are not included in the MANIFEST.MF as well as in the XXX.SF file. This creates a possibility for anyone to include malware codes inside these folders, repack the apk and resign it with the zipsigner application.

I was searching for a solution where i can prevent files being added into the META-INF folder and i found one from the below blog. But I'm unable to get the point of the solution. This looks like more of a research topic so there is not much information available in the internet. Can someone try and figure out the solution specified in the blog. The blog link is specified below the question.

http://blog.trustlook.com/2015/09/09/android-signature-verification-vulnerability-and-exploitation/

1 Answers

Answers 1

  1. Private key is never part of a distributed APK, unless I misunderstood your question. Someone else signing on your behalf is not possible unless your own system is hacked.

  2. The shared link (blog.trustlook.com) talks about Android skipping checking of files with .sf (and files with related extensions) extensions. So a malware could cloak itself in a file with one of these extensions. The fix mentioned there is an Android "system firmware" fix, not something that can be done at application level. This means, an OEM (Google itself, or Samsung/other) has to release an updated firmware to fix this. Check the latest updates, it might have been fixed already.

  3. In my opinion, even if an user sideloads APK's, this is more of a nuisance than a real attack/threat. Refer to the Blackhat paper below for further details - https://www.blackhat.com/docs/ldn-15/materials/london-15-Xiao-What-Can-You-Do-To-An-APK-Without-Its-Private-Key-wp.pdf

You should also read this for potential ways of tamper proofing APK - https://www.airpair.com/android/posts/adding-tampering-detection-to-your-android-app

Read More

Tuesday, May 3, 2016

Android App Users Get “App not installed” When Attempting to Update

Leave a Comment

UPDATE: To those who asked about which error codes the users are receiving: there are no error codes. It just opens a blank, post-installation page that says "The app was not installed" with a big 'X' next to it. It's possible different versions of Android could have different messages. There is no indication for what went wrong during the installation.

UPDATE 2: Some users reported that they receive error code "-504" when they try to install/update from the Play Store, and the "app not installed" message when manually trying to install the .apk. I don't know what correlation this error has with users being unable to install, but the solutions from the only 2 questions on SO on this topic did not fix anything for me. I've included the updated manifests and build files.

UPDATE 3: It appears as users report this issue in versions after IAB has been successfully installed, which further de-legitimatizes the concept that this issue is caused by introducing IAB.

UPDATE 4: It looks like the problem is with old users trying to update to a new version, and not with new users. With that in mind, there is a high likelihood that this issue is result of INSTALL_FAILED_UID_CHANGED. Looking through the version history, the significant change I made in the problematic version that users cannot update from is removing drawables that I no longer intended of using.

Asking users to go through the procedure to fix this isn't plausible. If there is a solution that I can enforce which would fix it for faulty users, wonderful... if not, the least I can do at this point is damage control and ensure this doesn't happen in the future.

NOTE: Below is the original post speculating that the problem is the result of introducing IAB into the app. Since then, it has become more and more unlikely for that to be the cause. Regardless, the post still has relevant information.

------------------------------------------------------------------------------------------

Original Title: Android App Users Get "App not installed" After Introducing IAB

I recently introduced IAB in my app that was published on Google Play. After a while, I've started to get reports from some users that they get an "installation unsuccessful" error when they try to install or update it. What makes me think it's caused by introducing IAB is that one particular long-time user e-mailed me that when he's attempting to update to the version with IAB, the installer mentions that new permissions were introduced and requires the user's permission. Once granted, it says that the app failed to install.

I've done some Googling and it appears to be a problem from their end, one user even tried to manually install an .apk with said permissions removed without any success. I wan't to make sure that it's not something I've done wrong, but an inevitability that I have to accept with some users.

Note that the vast majority has no problem of installing the app, and I haven't received any reports of this until after IAB was introduced. It wouldn't bother me so much were it a small amount of lost users, but the problem is, those users hurt my app's rating. Users have also mentioned that they can install apps, excluding my own, perfectly well.

I don't rule out the possibility that users may have been getting these errors even before IAB was introduced, and the linkage could be a mistaken one.

Here is my manifest:

<?xml version="1.0" encoding="utf-8"?> <manifest package = "com.jjsoftware.fullscientificcalculator"       xmlns:android = "http://schemas.android.com/apk/res/android">  <uses-permission android:name = "android.permission.VIBRATE"/> <uses-permission android:name = "com.android.vending.BILLING"/>  <application     android:allowBackup = "true"     android:fullBackupContent = "true"     android:icon = "@drawable/logo"     android:label = "@string/app_name">     <activity         android:name = ".MainActivity"         android:hardwareAccelerated = "false"         android:label = "@string/app_name"         android:screenOrientation = "portrait"         android:theme="@style/AppTheme">         <intent-filter>             <action android:name = "android.intent.action.MAIN"/>             <category android:name = "android.intent.category.LAUNCHER"/>         </intent-filter>     </activity>     <activity         android:name = ".SettingsActivity"         android:theme = "@style/PreferencesTheme">         <intent-filter>             <action android:name = ".SettingsActivity"/>             <category android:name = "android.intent.category.PREFERENCE"/>         </intent-filter>     </activity> </application> 

Here is the Gradle file:

apply plugin: 'com.android.application'  android {     compileSdkVersion 23     buildToolsVersion "23.0.1"      defaultConfig {         applicationId "com.jjsoftware.fullscientificcalculator"         minSdkVersion 14         targetSdkVersion 23         versionCode 102         versionName "1.679"     }      sourceSets { main { assets.srcDirs = ['src/main/assets', 'src/main/assets/'] } } }  dependencies {     compile 'com.android.support:appcompat-v7:23.1.1'     compile 'com.google.android.gms:play-services-ads:8.4.0'     compile 'com.android.support:gridlayout-v7:23.2.1'     compile files('libs/exp4j-0.4.5.jar')     compile files('libs/EJML-core-0.28.jar')     compile files('libs/EJML-dense64-0.28.jar')     compile files('libs/Jama-1.0.3.jar')     compile files('libs/EJML-simple-0.28.jar') } 

And, if need be, the top-level build:

// Top-level build file where you can add configuration options common to all sub-projects/modules.  buildscript {     repositories {         jcenter()     }     dependencies {         classpath 'com.android.tools.build:gradle:1.5.0'          // NOTE: Do not place your application dependencies here; they belong         // in the individual module build.gradle files     } }  allprojects {     repositories {         jcenter()     } } 

4 Answers

Answers 1

There is a typo in the manifest file on line android:largeHeap="true">>. xml line ends with >>. This may be causing the error.

Answers 2

Remember that the latest installment of Android (Marshmallow version) has changed the permissions to give more access to permissions to the user. Hence it is not enough to define the permissions in the manifest anymore.

Through code you need to make sure that the billing permission is enabled by the users when they use the app. The simplest way to go around this is to set the target SDK to v-22. This should temporarily solve your issue.

The real solution however is to handle the new permissions introduced in Marshmallow. Here is how to do it:

@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {      switch(requestCode) {         case BILLING_REQUEST:             if (canAccessBilling()) {                 callBillingPerms();             }             break;     } }  private void callBillingPerms() {     Toast.makeText(this, "We need your permission to access Billing", Toast.LENGTH_SHORT).show(); }  private boolean canAccessSMS() {     return(hasPermission(Manifest.vending.BILLING)); }  @TargetApi(Build.VERSION_CODES.M) private boolean hasPermission(String perm) {     return(PackageManager.PERMISSION_GRANTED==this.checkSelfPermission(perm)); } 

Hope this helps :)

Answers 3

it could be the phones have a lower version of the Google play services than the minimum you defined in the APK.

There is nothing much you can do if that is the case, other than for the users to upgrade their google services (https://play.google.com/store/apps/details?id=com.google.android.gms&hl=en) or you reduce your version.

also you may need to add the following to your manifest. (i think this is used to compare the versions installed in the phones with the versions required by the apk)

<application ...>      <!-- This meta-data tag is required to use Google Play Services. -->     <meta-data         android:name="com.google.android.gms.version"         android:value="@integer/google_play_services_version" />   </application> 

Answers 4

Perhaps the error is on the user's side.

This article states the following:

Google Play - Error 504

Problem

App could not be downloaded due to an error.

First solution

The usual, please: go to Settings > Apps > All > Google Play Store and Clear cache and Clear data. Also Clear cache and Clear data for Google Services Framework.

Second solution

Try removing your GMail account

This Stack Exchange answer discussed similar ideas.

According to the list of status codes at Wikipedia, a 504 error means the following:

504 Gateway Timeout
The server was acting as a gateway or proxy and did not receive a timely response from the upstream server.

Ask your users if doing the above solves their issue.

Read More