0

Requirements: I need to use adb to store a string value somewhere on an Android device that later is to be consumed by the app I'm programming upon first launch. The app is not installed when the String value is to be stored. The following requirements apply:

  • It must not require any runtime permissions that require user interaction to grant (adb grant is OK)
  • It must work on Android 12 and above
  • The String value must be able to change independently of the APK so it cannot be bundled
  • It cannot be passed though Instrumentation args (although this is for Android tests)

Methods attempted:

  • Store a file on a predefined location, like /sdcard/Downloads. Does not work because of tightened permission model from Android 11 and above
  • Store a file in the app local folder, like /sdcard/Android/data/com.my.app/files/. Does not work because the folder is cleared on install on some (not all) devices

edit: I need this for a specific CI/CD config scenario. This is not something I will ship into the wild.

Nilzor
  • 18,082
  • 22
  • 100
  • 167
  • Zero because I'm cleaning up after myself. Besides this is intended for CI/CD scenarios, not for production use – Nilzor Aug 10 '23 at 16:20
  • Let me reformulate: How many different values you expect on all devices to be ever used? – Robert Aug 10 '23 at 16:22
  • You should probably just be using assets. Your UI tests can have assets that are separate from the app itself. Although I would say storing a file method is completely viable- store the file after adb install but before launch – Gabe Sechan Aug 10 '23 at 16:33
  • I mentioned in the question "The app is not installed when the string value is to be stored", so the file method is not viable. Assets is not an option either since that would require alteration of the APK. I edited the question and added the requirement "The String value must be able to change independently of the APK" – Nilzor Aug 10 '23 at 16:46
  • "How many different values you expect on all devices to be ever used?" One for each device. We have a CI setup with 10 devices and each device needs a seldom-changing variable that is unique to that device which is to be picked up by the unit tests (It's a username) I don't want 10 different APKs. – Nilzor Aug 10 '23 at 16:51
  • Oh BTW I'm very aware I'm touching onto the XY Problem here. I'm asking this question to probe one of many possible solutions to my orginal problem. I think it's an interseting question on its own – Nilzor Aug 10 '23 at 16:53
  • 1
    If it is a unit test then simply implement a second app that is installed on each device and that allows you to store the username in it. And this app that is persistent (never uninstalled) has an interface (e.g. a content provider) which allows other apps (your unit test apps) to request this user name. How you store the username in this second app is up to you, just as you want. – Robert Aug 10 '23 at 21:18
  • 1
    As @Robert mentions, your best bet is a [content provider](https://developer.android.com/guide/topics/providers/content-providers) that it's uninstalled after you run the tests and contains the data you want to share (publicly) with the other apps that should use a [content resolver](https://developer.android.com/reference/android/content/ContentResolver) to find it. – Diego Torres Milano Aug 10 '23 at 21:56
  • 1
    You may want to consider using a custom system property: [How to define and use a system property in Android Instrumentation test?](https://stackoverflow.com/q/3750109/295004). Beyond normal dev mode access a non-root device restriction is that property names require 'debug.' prefix so `adb shell setprop debug.foobar 'galaxy' ` works but `adb shell setprop foobar 'galaxy' ` won't. – Morrison Chang Aug 10 '23 at 22:41
  • These are really good suggestions, why don't you post them as answers instead of comments? – Nilzor Aug 11 '23 at 06:22

1 Answers1

1

The closest solution to your requirements is to use a custom system property.

  • value only writable via adb
  • no root required
  • custom property requires 'debug.' prefix, so adb shell setprop debug.foobar 'customString' works while adb shell setprop foobar 'customString' won't work

Not sure how you didn't find How to define and use a system property in Android Instrumentation test?

but this answer works as tested on a Samsung Galaxy S9 Android 10 and a Pixel 6a Android 13.

Just be aware of when you are setting/unsetting custom system property values and when those are checked in the app under test, i.e. you may need to kill the app under test so that updated values are picked up.

As @Robert and @DiegoTorresMilano mentioned in the comments a ContentProvider/ContentResolver would be another solution. A second persistent app which would provide configuration test values to the app under test. That would be a solution for environments where 'developer mode' is unavailable OR where custom commands via adb impose a burden.

Morrison Chang
  • 11,691
  • 3
  • 41
  • 77