Showing posts with label android-manifest. Show all posts
Showing posts with label android-manifest. Show all posts

Saturday, October 21, 2017

Android Smart Banner — Manifest for Native App Install Complains About Missing Service Workers

Leave a Comment

I've read Google's documentation, googled around and looked through Stack Overflow, but haven't found any answers to this problem.

I need an Android Smart Banner to install a native app for the web site, and so (as per Google's instructions) have created the following manifest (details stubbed out for privacy reasons):

{   "short_name": "ShortName",   "name": "Longer App Name",   "start_url": ".",   "display": "standalone",   "icons": [     {          "src": "icon.png",          "type": "image/png",          "sizes": "144x144"      }   ],   "prefer_related_applications": true,   "related_applications": [     {          "platform": "play",          "id": "com.app.name"     }   ] } 

Since this is a native app, it doesn't require any service workers, according to Google's guidelines. However, when I open the site and try to add to the home screen (via the developer console), I keep getting the following error:

Site cannot be installed: no matching service worker detected. You may need to reload the page, or check that the service worker for the current page also controls the start URL from the manifest.

Do you know why this is happening? It would seem that this things this isn't a native app install, but why would it think that?

I noticed a few suspicious things from the get go, like the fact that it complained about me not having start_url and display, even though the guidelines don't mention it as necessary for a native app.

Could you tell me what I did wrong?

Thanks!

1 Answers

Answers 1

Reading google documentation i can only see some differences that i will put here so you can check:

  • Png Icon size should be 192x192
  • I would remove "start_url" and "display"
  • Be visited by the user twice, over two separate days during the course of two weeks. (This could be important also)
Read More

Monday, August 28, 2017

Android: converting standard XML to Android Binary XML format (AXML)

Leave a Comment

I want to convert a plaintext AndroidManifest.xml file into the binary format Android uses to package it inside the final APK.

I want to do this in Java, since I need to do it on the android device itself (which is why this question is NOT a duplicate of: How to convert XML to Android Binary XML. I know you can use AAPT, but I need a java method)

There's plenty of tools around to decode the binary xml into a readable file, but nothing on how to do the opposite, which is what I want.

Any info or hint on how this could be achieved is appreciated.

2 Answers

Answers 1

You may find a lot of command-line tools that can be used to compile and decompile the xml files for Android. Those tools are combined of several build tools including aapt (Android Asset Packaging Tools) to view, create, and update Zip-compatible archives (zip, jar, apk). Since This tool is a part of the Android SDK, There's no native implementation of it in Java.

Fortunately, self-compile-Android repository has all the necessary files in Java Native Interface (JNI). They are ready to be used from inside an Android App and capable of self-compilation, mutation, and viral spreading.

Here a list of available native modules in the app:

aapt -> Platform_Framework_Base\tools\aapt aidl -> Platform_Framework_Base\tools\aidl androidfw -> Platform_Framework_Base\include\androidfw  zipalign -> Platform_Build\tools\zipalign host -> Platform_Build\lib\host  libpng -> Platform_External_Libpng expat -> Platform_External_Expat zlib -> Platform_External_Zlib  libcutils -> Platform_System_Core\libcutils cutils -> Platform_System_Core\include\cutils  liblog -> Platform_System_Core\liblog log -> Platform_System_Core\include\log  libutils -> Platform_System_Core\libutils utils -> Platform_System_Core\include\utils  log.h -> Platform_System_Core\include\android  asset_manager.h -> Platform_Framework_Native\include\android looper.h -> Platform_Framework_Native\include\android  zopfli -> zopfli\src  ld -> Tool_Chain_Utils\binutils-2.25\ld 

If you look closely at the source you'll find the app executing aapt commands using the native jni files:

private void runAapt() throws Exception {     Util.deleteRecursive(new File(S.dirRes, "drawable-xxhdpi"));      Aapt aapt = new Aapt();     int exitCode = aapt.fnExecute("aapt p -f -v -M " + S.xmlMan.getPath() + " -F " + S.ap_Resources.getPath()             + " -I " + S.jarAndroid.getPath() + " -A " + S.dirAssets.getPath() + " -S " + S.dirRes.getPath()             + " -J " + S.dirGen.getPath());      if (exitCode != 0) {         throw new Exception("AAPT exit(" + exitCode + ")");     } } 

Now, go through the sample code to see how the functionalities are implemented. For example to change a value in manifest file,

private void modifyManifest() throws Exception {         Document dom = Util.readXml(S.xmlMan);          dom.getDocumentElement().getAttributes().getNamedItem("package").setNodeValue(userInput.appPackage);          Transformer t = tf.newTransformer();         t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");         t.setOutputProperty(OutputKeys.INDENT, "yes");         t.setOutputProperty(OutputKeys.METHOD, "xml");         t.setOutputProperty(OutputKeys.VERSION, "1.0");         t.setOutputProperty(OutputKeys.ENCODING, "UTF-8");         t.transform(new DOMSource(dom), new StreamResult(new FileOutputStream(xmlFile)));     }  

Answers 2

Your problem boils down to how can you run aapt on the Android device itself.

Since aapt is open source, the best solution is just build it yourself!

Plenty of people have already done that - and indeed there are examples in the Play Store. See http://talc1.loria.fr/users/cerisara/posts/buildandroid/ for instructions on how to use aapt obtained from the AIDE app. A search on the Play Store turns up plenty of other Android IDEs which also offer aapt functionaility.

Read More

Tuesday, April 11, 2017

ionic build number wrong in config.xml file

Leave a Comment

My problem is that if I compile my project, it adds a 2 to the build number.

My Ionic config.xml

<widget id="at.company.or.so" version="0.0.1" ios-CFBundleVersion="55" android-versionCode="72" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0"> 

My AndroidManifest.xml

<manifest android:hardwareAccelerated="true" android:versionCode="72" android:versionName="0.0.1" package="at.tiddlr.app" xmlns:android="http://schemas.android.com/apk/res/android"> 

If i build a debug or release Version should be 0.0.1(72) but when i install the App it is 0.0.1(722)

Output of aapt aapt d badging apk.apk

package: name='at.company.or.so' versionCode='722'  versionName='0.0.1'platformBuild VersionName='5.1.1-1819727' sdkVersion:'14' targetSdkVersion:'22' 

I think it's a problem while compiling but i have no idea where to search.

1 Answers

Answers 1

Not sure if you still have an issue with this, but I ran into the same build issue with Android where mine would increment with an 8. My solution for now is to..... dramatic pause.... comment out some lines in the build.gradle file. Whenever I upgrade the CLI I have to go do it again....

This line:

versionCode cdvVersionCode ?: Integer.parseInt("" + privateHelpers.extractIntFromManifest("versionCode") + "0") 

Change to:

versionCode cdvVersionCode ?: Integer.parseInt("" + privateHelpers.extractIntFromManifest("versionCode")) 

Then I also comment out the whole if/else block about 13 lines down which starts with:

if (Boolean.valueOf(cdvBuildMultipleApks)) { 

Now I have to manually update my build number for android before I deploy to the store in the config file, but my increment issue has stopped. Hopefully this help somebody out if you have already passed the issue. I have included a link to the issue on Apache's issues board below. IF the link ever dies check out CB-8976 on Apache's issue site. I will also note that I have not experienced any issues with commenting this out... but I can not guarantee since you should not mess with this file technically as they state // GENERATED FILE! DO NOT EDIT!)

Apache Issue's / Version Code

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

Tuesday, March 15, 2016

Extract / distinguish ActivityAlias name from TargetActivity

Leave a Comment

I have multiple ActivityAliases which all start one single TargetActivity. Inside of my TargetActivity I try to distinguish the alias that started the TargetActivity.

The aliases are defined in Manifest as launchables (intent-filter), which will be displayed as shortcuts on the homescreen. The user will click on the shortcut and android will start the activity, which I defined in the "android:targetActivity=.." tag.

For that I currently extract the componentName from the Intent, which is given to my TargetActivity and using the className().

Like:

String aliasName = targetActivity.getComponentName().getClassName(); 

This works fine for a lot of devices. But currently I see some failures on the OnePlus. At that device, my technique only returns the className of my TargetActivity and therefore I can't deliver the action, based on the alias that the user started.

Are there any other, reliable methods to get ActivityAlias that was used to start the TargetActivity? It does not need to be the name itself, as long as I can distinguish them. I do not want to create dedicated TargetActivities for every Alias!

Thanks!

Ps.: I saw another way, which uses the PackageManager to retrieve the activityInfo and using the Activity.name. But I doubt that this will return something different than my first approach.

ActivityInfo aInfo = activity.getPackageManager().getActivityInfo(activity.getComponentName(), PackageManager.GET_META_DATA);  String aliasName = aInfo.name; 

I also tried meta-data:

Edit:

Unfortunately this method does not work for all devices. If the parsed alias-className from the activity.component returns the target-activity, then the meta-data approach fails, too.

I continued searching for an answer and found a good workaround to distinguish between my aliases inside of the TargetActivty.

You can provide meta-data within your ActivityAlias tag like so:

<activity-alias      android:name=".aliasName"      android:enabled="false"      android:exported="true"      android:icon="@drawable/someIconRes"      android:label="@string/someLabelRes" android:targetActivity=".yourTargetActivity">      <meta-data android:name="alias" android:value="valueToDistinguish"/>     <intent-filter>           <action android:name="android.intent.action.MAIN"/>          <category android:name="android.intent.category.LAUNCHER"/>      </intent-filter>  </activity-alias> 

The important part here is:

<meta-data android:name="alias" android:value="valueToDistinguish"/> 

Which is within the <activity-alias> here </activity-alias> tag.

To extract the meta-data you can get an ActivityInfo from the PackageManager with the TargetActivity:

ActivityInfo appInfo = activity.getPackageManager().getActivityInfo(activity.getComponentName(), PackageManager.GET_META_DATA); 

And extract the meta-data via:

    private static String getAliasNameByMetaData(ActivityInfo app) {     String aliasName = "";     if (app.metaData != null && app.metaData.containsKey(ALIAS_META_DATA_KEY)) {         aliasName = app.metaData.getString(ALIAS_META_DATA_KEY, "");     } else {         LOG.i("AliasName by META-DATA didn't work!");     }     LOG.v("AliasName by META-DATA: " + aliasName);     return aliasName; } 

Edit:

Inspecting the Activity class using the debugger, it includes a mActivityInfo field that is different from the ActivityInfo returned by getPackageManager().getActivityInfo() so you can extract it using reflection and check it's name.

Note: It seems that the ActivityInfo returned by getPackageManager().getActivityInfo() is a shallow copy of the mActivityInfo from the Activity. So, maybe this method does not resolve the issue:

Field field = Activity.class.getDeclaredField("mActivityInfo"); field.setAccessible(true); ActivityInfo value = (ActivityInfo) field.get(this); Log.e("APPINFO2", "NAME: " + value.name); 

0 Answers

Read More