bitstadium / HockeySDK-Cordova

HockeyApp was retired and the SDKs are deprecated. Please use App Center instead.
https://github.com/microsoft/appcenter-sdk-cordova
Other
82 stars 73 forks source link

Conflicting android.permission.WRITE_EXTERNAL_STORAGE permissions #100

Closed bmcharg closed 6 years ago

bmcharg commented 6 years ago

I'm having some problems installing the HockeySDK-Cordova plugin in my project on Android. Everything works fine on iOS, but when I install the SDK it appears to cause a permissions conflict with another plugin used in my app.

Without the Hockey plugin installed, my app has the following key in platforms/android/AndroidManifest.xml

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Everything in my app function as expected, and from the other plugin data can written to external storage.

However, the minute I install the HockeySDK things start to go awry, and the other plugin can no longer write to the external storage. Although my platforms/android/AndroidManifest.xml remains the same once Hockey is installed, I do notice the following in /platforms/android/build/intermediates/exploded-aar/HockeySDK-Android-5.1.0/AndroidManifest.xml

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />

This same value key can also be found in /platforms/android/build/intermediates/manifests/full/debug/AndroidManifest.xml

I believe that this is what is causing the problem, in that for anything >sdk18 the WRITE_EXTERNAL_STORAGE permission is being removed. Indeed, when installing on some devices I can see the requested permissions includes READ_EXTERNAL_STORAGE but not WRITE_EXTERNAL_STORAGE.

To further back this up, if I remove the Hockey plugin, everything works again in our plugin and in the app as a whole.

How is a conflict like this resolved? We need WRITE_EXTERNAL_STORAGE enabled for ALL sdks, not just those <18.

Thanks in advance for any help.

bmcharg commented 6 years ago

I've found a bit more info in https://support.hockeyapp.net/kb/client-integration-android/hockeyapp-for-android-sdk#permissions-advanced which seems to be for exactly this issue. However, I can't seem to find the correct syntax for my plugin.xml to ensure this is honoured.

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace"/>

Should this be in my plugin.xml, or should it actually be in the AAR included in this plugin?

ElektrojungeAtWork commented 6 years ago

Hi Brian,

I just responded to the ticket that you opened in our support. We are looking into this and will be in touch. Let's use the support for all discussion.

I'll update this issue as soon as we've found a solution that works for you.

Best, Benjamin

bmcharg commented 6 years ago

Great, thanks Ben. Sounds like a plan.

rahulbpatel commented 6 years ago

What is the support ticket? This just bit me in combination with the cordova-camera-plugin

ElektrojungeAtWork commented 6 years ago

Hey @rahulbpatel,

I cannot share support conversations with you as they are private. That said, can you try using the "remove" instead of "replace"? <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove" /> This is not guaranteed to work but might be in your case. We're currently still trying to find a solution for this issue that works reliably.

Best, Benjamin

rahulbpatel commented 6 years ago

Hi @TroubleMakerBen,

Where am I adding this? I'm working on an Ionic / Cordova project and am only working with config.xml. Should I be editing another file?

rahulbpatel commented 6 years ago

Hi, I think adding this to config.xml does the trick:

<edit-config file="AndroidManifest.xml" mode="merge" target="/manifest/uses-permission[@android:name='android.permission.WRITE_EXTERNAL_STORAGE']">
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace" />
</edit-config>
rahulbpatel commented 6 years ago

The above doesn't work on a clean platform add.

rahulbpatel commented 6 years ago

This seemed to work better:

<edit-config file="AndroidManifest.xml" mode="merge" target="/manifest">
  <manifest xmlns:tools="http://schemas.android.com/tools" />
</edit-config>
<config-file parent="/manifest" target="AndroidManifest.xml">
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace" />
</config-file>
ElektrojungeAtWork commented 6 years ago

@rahulbpatel does that solve the issue for you?

snow-dev commented 6 years ago

Problem is on native too, here the above solution work's perfectly, so I'm gonna try on one of my Ionic project.

On Feb 6, 2018 3:25 PM, "Benjamin Scholtysik (Reimold)" < notifications@github.com> wrote:

@rahulbpatel https://github.com/rahulbpatel does that solve the issue for you?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/bitstadium/HockeySDK-Cordova/issues/100#issuecomment-363569716, or mute the thread https://github.com/notifications/unsubscribe-auth/ACpP_XItdHKxyy7bfYffRKXz5rVdSk5hks5tSMNdgaJpZM4Rv8v1 .

rahulbpatel commented 6 years ago

@TroubleMakerBen yes, now I can build and take pictures.

The cordova build does show a warning message:

Conflict found, edit-config changes from config.xml will overwrite plugin.xml changes

But I think it's expected since we're trying to do this on purpose.

ElektrojungeAtWork commented 6 years ago

Thx for the info @rahulbpatel!

I'm leaving this issue open for better visibility.

Sam-Victor-S commented 6 years ago

After installed this hockey app plugin my native camera plugin not working. I am using ionic 3 and angular 4 .After uninstall this plugin my native camera is working fine.Kindly give me the solution

rahulbpatel commented 6 years ago

Re my comment on Feb 6 I ran into further issues when actually uploading the APK to Google Play: hepcure_googleplay

The issue was that in some build sequences the <config-file> approach was adding a duplicate <uses-persmission> element for android.permission.WRITE_EXTERNAL_STORAGE. Ultimately, what I had to do was use a before_build hook to modify the AndroidManifest.xml file:

config.xml

<edit-config file="AndroidManifest.xml" mode="merge" target="/manifest">
  <manifest xmlns:tools="http://schemas.android.com/tools" />
</edit-config>
<hook src="scripts/hooks/fix_hockeyapp_android_write_external_storage_max_sdk_version_issue.js" type="before_build" />

/scripts/hooks/fix_hockeyapp_android_write_external_storage_max_sdk_version_issue.js

'use strict';

const fs = require('fs');
const xml2js = require('xml2js');

module.exports = function (context) {
  const parseString = xml2js.parseString;
  const builder = new xml2js.Builder();
  const manifestPath = context.opts.projectRoot + '/platforms/android/AndroidManifest.xml';
  const androidManifest = fs.readFileSync(manifestPath).toString();

  let manifestRoot;

  if (androidManifest) {

    parseString(androidManifest, (err, manifest) => {

      if (err) {
        return console.error(err);
      }

      manifestRoot = manifest['manifest'];

      if (!manifestRoot['uses-permission']) {
        manifestRoot['uses-permission'] = [];
      }

      var permission = manifestRoot['uses-permission'].find(function(item) {
        return item['$']['android:name'] === 'android.permission.WRITE_EXTERNAL_STORAGE';
      });

      if(permission) {

        permission['$']['tools:node'] = 'remove';
        fs.writeFileSync(manifestPath, builder.buildObject(manifest));
      }
    });
  }
};

This hook adds a tools:node="remove" attribute to the first <uses-persmission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> element in AndroidManifest.xml. When the full merged AndroidManifest.xml is generated, the permissions added by the HockeyApp .aar would be the one that was removed. This is pretty confusing but hope it helps if my previous solution doesn't work.

cchcc commented 6 years ago

I had a problem when request permission of WRITE_EXTERNAL_STORAGE because of this. and solved this by following.

  1. unzip aar

    $ unzip HockeySDK-Android-5.1.0.aar -d HockeySDK-Android-5.1.0
  2. edit AndroidManifest.xml from extracted folder

    <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="18" />

    to

    <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  3. zip aar

    $  jar cvf HockeySDK-Android-5.1.0.aar -C HockeySDK-Android-5.1.0/ .

replace to new aar file.

mikeThurmond commented 6 years ago

Has anyone else had luck with the hook above? I am still having issues android.permission.WRITE_EXTERNAL_STORAGE

bmourat commented 6 years ago

Hi @mikeThurmond,

Could you please provide error context if any? Also, please check if your AndroidManifest.xml file is located under /platforms/android path.

Best, Murat

mikeThurmond commented 6 years ago

@bmourat I found a solution, I had to change the hook type to "after_prepare" for some reason as well as editing the path to the android manifest. Thanks

raujonas commented 5 years ago

@snow-dev @mikeThurmond Did you manage to get it work in an Ionic project? I tried the steps mentioned above, but my app still crashes during runtime when I try to open the camera. Without the plugin added it works perfectly.

bmourat commented 5 years ago

Hi @raujonas Could you please describe what steps did you try and how does your resulting manifest looks like?

mikeThurmond commented 5 years ago

@raujonas I did get it to work, I did the following:

I took the hook from above and made a couple changes. I also had to import the libraries fs and xml2js via node or homebrew (it was one of the two, I just can't remember)

1) I had to edit the path of this line from const manifestPath = context.opts.projectRoot + '/platforms/android/AndroidManifest.xml'; to '/platforms/android/app/src/main/AndroidManifest.xml'

you might have to edit the path to something else, just check and make sure it lines up to your android manifest file during the build/prepare steps

2) I changed this line near the bottom from

permission['$']['tools:node'] = 'remove';
to permission['$']['tools:node'] = 'replace';

I added this line to the config.xml and changed the type to after_prepare

I had to reference the Cordova docs on hooks to help with this step.

Hope this helps

raujonas commented 5 years ago

@bmourat @mikeThurmond thank you for your help! These are the steps I tried:

  1. I installed the plugin like it is mentioned here: https://www.npmjs.com/package/ionic-hockeyapp. After this step I get the error 20 as expected when I will use the camera.

  2. Then I added the javascript file from above. My AndroidManifest.xml is in the same path as yours, so I changed the path also to const manifestPath = context.opts.projectRoot + '/platforms/android/app/src/main/AndroidManifest.xml';

  3. I also changed the permission at the end of the file: permission['$']['tools:node'] = 'replace';

  4. Then I added the hook to my config.xml, where I changed the type also to after_prepare: `

    `

After I did these steps, I do not get the error 20 as before when I open the camera. The camera opens, but then my app crashes without any further information. So I had the idea to consider logcat:

11-25 10:30:47.110 17919 17919 D CordovaActivity: Paused the activity. 11-25 10:30:47.127 17919 18012 W PluginManager: THREAD WARNING: exec() call to Camera.takePicture blocked the main thread for 131ms. Plugin should use CordovaInterface.getThreadPool(). 11-25 10:30:47.127 1653 1667 E memtrack: Couldn't load memtrack module 11-25 10:30:47.127 1653 1667 W android.os.Debug: failed to get memory consumption info: -1 11-25 10:30:47.131 17919 17919 D CordovaWebViewImpl: >>> loadUrl(javascript:cordova.plugins.backgroundMode._setActive(true);cordova.plugins.backgroundMode.onactivate(null);cordova.plugins.backgroundMode.fireEvent('activate',null);) 11-25 10:30:47.182 1653 1667 E memtrack: Couldn't load memtrack module 11-25 10:30:47.183 1653 1667 W android.os.Debug: failed to get memory consumption info: -1 11-25 10:30:47.187 3029 3029 V CAM_QuickActivity: START onCreate: Activity = com.android.camera.CaptureActivity@8c4e868 11-25 10:30:47.187 3029 3029 V CAM_Profiler: [ 0.000ms][ui] GUARD: CameraActivity.onCreateTasks - START 11-25 10:30:47.188 3029 3029 D CAM_LocationManager: Using legacy location provider. 11-25 10:30:47.202 3029 3029 W SoundPool: Use of stream types is deprecated for operations other than volume control 11-25 10:30:47.202 3029 3029 W SoundPool: See the documentation of SoundPool() for what to use instead with android.media.AudioAttributes to qualify your playback use case 11-25 10:30:47.202 3029 3029 I CAM_OneCamFtrCnfgCrtr: CaptureModule? true 11-25 10:30:47.203 3029 3029 V CAM_Profiler: [ 15.525ms][ui] GUARD: CameraActivity.onCreateTasks - [ 0.100ms] Glide.setup 11-25 10:30:47.213 1653 1667 E memtrack: Couldn't load memtrack module 11-25 10:30:47.215 1653 1667 W android.os.Debug: failed to get memory consumption info: -1 11-25 10:30:47.216 3029 3029 V CAM_Profiler: [ 26.122ms][ui] GUARD: CameraActivity.onCreateTasks - [10.597ms] OneCameraManager.get 11-25 10:30:47.228 3029 18136 V NuMediaExtractor: setDataSource fd=147 (/system/media/audio/ui/camera_click.ogg), offset=0, length=5951 11-25 10:30:47.242 17919 17919 W zygote64: Attempt to remove non-JNI local reference, dumping thread 11-25 10:30:47.264 1653 1667 E memtrack: Couldn't load memtrack module 11-25 10:30:47.264 1653 1667 W android.os.Debug: failed to get memory consumption info: -1 11-25 10:30:47.264 17919 17919 D AndroidRuntime: Shutting down VM 11-25 10:30:47.266 17919 17919 E AndroidRuntime: FATAL EXCEPTION: main **11-25 10:30:47.266 17919 17919 E AndroidRuntime: java.lang.RuntimeException: Unable to create service de.appplant.cordova.plugin.background.ForegroundService: java.lang.SecurityException: Neither user 10062 nor current process has android.permission.WAKE_LOCK.** 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at android.app.ActivityThread.handleCreateService(ActivityThread.java:3349) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at android.app.ActivityThread.-wrap4(Unknown Source:0) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1677) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at android.os.Looper.loop(Looper.java:164) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6494) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: Caused by: java.lang.SecurityException: Neither user 10062 nor current process has android.permission.WAKE_LOCK. 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:2004) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:1950) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at android.os.IPowerManager$Stub$Proxy.acquireWakeLock(IPowerManager.java:405) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at android.os.PowerManager$WakeLock.acquireLocked(PowerManager.java:1352) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at android.os.PowerManager$WakeLock.acquire(PowerManager.java:1318) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at de.appplant.cordova.plugin.background.ForegroundService.keepAwake(ForegroundService.java:124) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at de.appplant.cordova.plugin.background.ForegroundService.onCreate(ForegroundService.java:94) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: at android.app.ActivityThread.handleCreateService(ActivityThread.java:3339) 11-25 10:30:47.266 17919 17919 E AndroidRuntime: ... 8 more

What makes me wonder is the following log entry: 11-25 10:30:47.266 17919 17919 E AndroidRuntime: java.lang.RuntimeException: Unable to create service de.appplant.cordova.plugin.background.ForegroundService: java.lang.SecurityException: Neither user 10062 nor current process has android.permission.WAKE_LOCK.

So I suggest that there is now a problem with another plugin?

Edit: Before I added the hook above, I have the following permission in my manifest: `

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />`

After I added the hook, there are only these permissions:

`

`

So you can see that the permission "WAKE_LOCK" which lead to the crash of my app is missing. Can I achieve to hold the old permissions when running the hook?

raujonas commented 5 years ago

Hey guys, thank you again for your help! I think sometimes it just helps to write all steps down and to think about them again, so it seems that it is working now.

What I did in fact is deleting the platforms and plugins folder and then started a new build. I could image that the permissions I mentioned above are missed after the build, because I tried with the "remove" value instead the "replace" on my first try. Now the script handles all permissions correctly and I can use the camera without a crash (because the were in the manifest from the beginning).

Thank you again! Maybe this helps also someone else.

arajanrai commented 5 years ago
<edit-config file="AndroidManifest.xml" mode="merge" target="/manifest">
  <manifest xmlns:tools="http://schemas.android.com/tools" />
</edit-config>
<config-file parent="/manifest" target="AndroidManifest.xml">
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace" />
</config-file>

also remove platform folder

parthnayak7448 commented 5 years ago

@bmourat , @raujonas , @mikeThurmond , @arajanrai Can anyone please mention all the steps properly from path of all the files where we have to replace XXX lines. While just mentioning change this line to this is not happening for us. It will be great if anyone write files path and changes for that file.

annakocheshkova commented 5 years ago

Hi @parthnayak7448 ! Sure, here are the detailed steps: So lets say you have an app named TestApp.

  1. Remove TestApp/platforms folder;
  2. Open your config.xml and add the following lines:
    <edit-config file="AndroidManifest.xml" mode="merge" target="/manifest">
    <manifest xmlns:tools="http://schemas.android.com/tools" />
    </edit-config>
    <hook src="scripts/hooks/fix_hockeyapp_android_write_external_storage_max_sdk_version_issue.js" type="after_prepare" />
  3. In the root of your project, create a folder named scripts, and under it a folder named hooks;
  4. Put the following file with the name fix_hockeyapp_android_write_external_storage_max_sdk_version_issue.js into hooks:
    
    'use strict';

const fs = require('fs'); const xml2js = require('xml2js');

module.exports = function (context) { const parseString = xml2js.parseString; const builder = new xml2js.Builder(); const manifestPath = context.opts.projectRoot + '/platforms/android/AndroidManifest.xml'; const androidManifest = fs.readFileSync(manifestPath).toString(); let manifestRoot;

if (androidManifest) { parseString(androidManifest, (err, manifest) => {
if (err) { return console.error(err); } manifestRoot = manifest['manifest'];

  if (!manifestRoot['uses-permission']) {
    manifestRoot['uses-permission'] = [];
  }

  var permission = manifestRoot['uses-permission'].find(function(item) {
    return item['$']['android:name'] === 'android.permission.WRITE_EXTERNAL_STORAGE';
  });

  if(permission) {
    permission['$']['tools:node'] = 'replace';
    fs.writeFileSync(manifestPath, builder.buildObject(manifest));
  }
});

} };


Make sure that the path `const manifestPath = context.opts.projectRoot + '/platforms/android/AndroidManifest.xml';` is correct and leads to your `AndroidManifest.xml`;
5. `npm i xml2js`;
6. `cordova platform add android`;
7. Start the app.

I also noticed that this fix does not work with `cordova >= 7.0.0`. So if you have higher cordova versions:
1. In step 2, paste only this line: `
<hook src="scripts/hooks/fix_hockeyapp_android_write_external_storage_max_sdk_version_issue.js" type="after_prepare" />`
2. Change the following line in the `fix_hockeyapp_android_write_external_storage_max_sdk_version_issue` script:
`const manifestPath = context.opts.projectRoot + '/platforms/android/AndroidManifest.xml';`
to this line:
`const manifestPath = context.opts.projectRoot + '/platforms/android/app/src/main/AndroidManifest.xml';`
3. In the `fix_hockeyapp_android_write_external_storage_max_sdk_version_issue` script, add the following line:
`manifestRoot['$']['xmlns:tools'] = 'http://schemas.android.com/tools';`
after this line:
`manifestRoot = manifest['manifest'];`.

Let me know how this works for you.
parthnayak7448 commented 5 years ago

Hey @annakocheshkova ,

Thanks for brief description. But still this solution didn't work for me and giving same error '20'

Android: 8.0.0 Ionic 3

annakocheshkova commented 5 years ago

Hi @parthnayak7448, sorry for the issues you are experiencing. Your cordova-android version is 8.0.0, right? Can you share your config.xml contents with me? Thanks!

parthnayak7448 commented 5 years ago

Hey @annakocheshkova

My Android version is 8.0.0.

`<?xml version='1.0' encoding='utf-8'?>

test test need location access to find things nearby

`

annakocheshkova commented 5 years ago

Hi @parthnayak7448! I don't see <hook src="scripts/hooks/fix_hockeyapp_android_write_external_storage_max_sdk_version_issue.js" type="after_prepare" /> line in the config. My bad, seems like it is necessary on all android versions. I've edited my comment to reflect that.

annakocheshkova commented 5 years ago

@parthnayak7448 just a friendly ping :) Did you manage to get it working?

ParthNayak5487 commented 5 years ago

Hi @annakocheshkova

I don't see <hook src="scripts/hooks/fix_hockeyapp_android_write_external_storage_max_sdk_version_issue.js" type="after_prepare" /> line in the config. My bad, seems like it is necessary on all android versions. I've edited my comment to reflect that.

Sorry before sending you config i have remove hook tag because as i told it was not working so undo all the steps that i followed.

just a friendly ping :) Did you manage to get it working?

Anna i haven't try after that. my main concern to use hockey app was to get error reports which i replace with app centre plugin. But for sure i will try again very soon and will update you later on.