We are developing a COSU app using Android Management API and QR code provisioning. We're planning to distribute app with private Google play, but for now I'm trying to make it work with manual installation using apk. That's how it should work:
A client receives qr code from us, that applies policy without restrictions to the device.
After provisioning client downloads apk from some other source (probably via email) and installs it.
Client applies policy with restrictions from app with call to API.
So, I'm stuck on second step - an attempt to install downloaded apk leads to this error:
Default policy seems to be ok:
{
"name": "enterprises/<enterpriseName>/policies/policy_unlocked",
"version": "11",
"applications": [
{
"packageName": "com.axmor.fsinphone",
"installType": "AVAILABLE",
"defaultPermissionPolicy": "GRANT"
}
],
"persistentPreferredActivities": [
{
"receiverActivity": "com.axmor.fsinphone",
"actions": [
"android.intent.action.MAIN"
]
}
],
"systemUpdate": {
"type": "WINDOWED",
"startMinutes": 120,
"endMinutes": 240
},
"debuggingFeaturesAllowed": true
}
]
}
And this policy is applied to device:
"policyName": "enterprises/<enterpriseName>/policies/policy_unlocked",
"appliedPolicyName": "enterprises/<enterpriseName>/policies/policy_unlocked",
What I've tried:
Installing release apk and signed apk (same result)
Installing apk with adb from Android studio - this works, but it's not what I want.
(copying the solution here from comments)
To be able to install apps from outside the Play Store you need to set installUnknownSourcesAllowed to true in the Policy. More details in the policy references.
Related
I am using Android Management API to run my APP in Kiosk Mode. It's relying on a USB Device to work correctly, but the prompt for accepting the connection throws an LOCK TASK MODE VIOLATION Error.
At this moment my App gets stuck (propably since the authorization prompt can't be displayed) and can only be reset by reboot.
As explained in this post you can whitelist com.android.systemui, but how can this be applied to the Android Management API?
Alright, i figured it out. I reread this section of the management api documentation. Seems like this is the way to "whitelist" apps for Lock Task Mode, although it's a bit misleading.
So you simply just add the packages as "FORCE_INSTALLED" to your policy, even already installed packages from your system. So in my case:
{
...
"applications": [
{
"packageName": "com.example.app",
"installType": "KIOSK",
"defaultPermissionPolicy": "GRANT"
},
{
"packageName": "com.android.systemui",
"installType": "FORCE_INSTALLED",
"defaultPermissionPolicy": "GRANT"
}
]
}
I used this quick start guide to setup my project and enterprise. Currently the project is under 'No Organization' on the Google Cloud Console hierarchy.
I have setup the following device policy with a single app in kiosk mode. The app is restricted to a single country and is developed in-house.
{
"safeBootDisabled": true,
"screenCaptureDisabled": true,
"factoryResetDisabled": true,
"systemUpdate": {
"type": "WINDOWED",
"startMinutes": 0,
"endMinutes": 240
},
"applications": [
{
"packageName": "com.xxx.yyy",
"installType": "KIOSK",
"defaultPermissionPolicy": "GRANT"
}
],
"debuggingFeaturesAllowed": true,
"funDisabled": true,
"appAutoUpdatePolicy": "WIFI_ONLY",
"kioskCustomization": {
"statusBar": "NOTIFICATIONS_AND_SYSTEM_INFO_ENABLED"
}
}
I currently use the QR method to provision devices.
The problem I am having is that the provisioning process is failing at the stage when the app is being installed.
When I use this API to check what went wrong I can see that it failed because of the following error:
{
"nonComplianceDetails": [
{
"settingName": "applications",
"nonComplianceReason": "APP_NOT_INSTALLED",
"packageName": "com.xxx.yyy",
"installationFailureReason": "NOT_AVAILABLE_IN_COUNTRY"
},
{
"settingName": "persistentPreferredActivities",
"nonComplianceReason": "APP_NOT_INSTALLED",
"packageName": "com.xxx.yyy"
}
]
}
If I change my device policy from install type "KIOSK" to "AVAILIBLE" the device is successfully provisioned. I can then install the app from the Play store and reset the install type to "KIOSK" mode.
But this is far from ideal because the entire device fleet of 85 production devices settings', are then changed just to provision a single device.
So it seems that while provisioning the device the location settings are incorrect?
Does anybody know why this is happening?
Try to create a separate policy just for this device so that you can provision it without affecting other devices, and once provisioned, you can update which policy is applied to the device to be the same to all other devices.
You can use policies.patch to update the policy or devices.patch.
This also could be for a lack of Kiosk support mode for a given app as KIOSK required the app to have an official “lock task mode” per https://developer.android.com/work/dpc/dedicated-devices/lock-task-mode.
I have a react-native app with multiple environments.
Dev, prod, ... Which means that I have multiple 'copies' of the app installed on the phone App Dev, App Prod.
These are under a different bundle identifier:
com.myapp.dev
com.myapp.prod
I use deep links to open the app, this works perfect on Android because it asks with which app you want to open it, but on iOS it just opens the first app that founds installed 😞 and i can't find the way to, for example:
Launch develop-app://whatever/1 and open it in the Dev app
Launch prod-app://whatever/1 and open it in the Prod app
What am i missing?
This are my defined url types:
Also the apple-app-site-association file looks like this:
{
"applinks": {
"apps": [],
"details": [
{
"appID": "1234.com.myapp.dev",
"paths": ["*"]
},
{
"appID": "1234.com.myapp.prod",
"paths": ["*"]
}
]
}
}
Update
The first problem that i found was that the apple-app-site-association wasn't using a Content-Type header, so, the app could not recognize the file.
The paths that each environment should recognize should be defined:
{
"applinks": {
"apps": [],
"details": [
{
"appID": "1234.com.myapp.dev",
"paths": ["/dev/*"]
},
{
"appID": "1234.com.myapp.prod",
"paths": ["/prod/*"]
}
]
}
}
Now i'm able to see the banner on the top of the website Open with App Dev as expected
You have to specify which path is to be opened by which app
For example, your domain is example.com
You have to specify a different path pattern for both dev & prod app in your apple-app-site-association file
For example, you can update your apple-app-site-association file as shown below
{
"applinks": {
"apps": [],
"details": [
{
"appID": "1234.com.myapp.dev",
"paths": ["/dev/*"]
},
{
"appID": "1234.com.myapp.prod",
"paths": ["/prod/*"]
},
]
}
}
Now, let us say you click on the urls below, you'll be directed to mentioned app in the comments
https://example.com/dev/123?id=3 // Opens dev app
https://example.com/dev?id=2 // Opens dev app
https://example.com/prod/123 // Opens prod app
https://example.com/prod // Opens prod app
https://example.com/prod/123?name=john // Opens prod app
I have an android app that renders a MapView and polylines, which works fine on the Android emulator if I use an IP restricted API key, but doesn't even display a map, and definitely no polylines, when I use an android restricted key with the expo built application running on my phone.
I have the following in my app.json:
{
"expo": {
"android": {
"package": "com.company.project",
"permissions": [ "CAMERA" ],
"config": {
"googleMaps": {
"apiKey": "ACTUAL_API_KEY_HERE"
}
}
},
...
The directions portion of the code is as follows:
const key = Constants.manifest.android.config.googleMaps.apiKey;
const resp = await fetch(`https://maps.googleapis.com/maps/api/directions/json?origin=${ startLoc }&destination=${ destinationLoc }&key=${ key }`);
const respJson = await resp.json();
I am building my app with the following command:
expo build:android
I then download the apk from expo.io.
The key is restricted to android apps in the GCP console. I have verified that the package name in my app.json matches the name in the restriction and I get the SHA-1 fingerprint from the "expo fetch:android:hashes" command.
As I said, this works fine in the emulator (with an IP restricted key) but not when running on my phone. Am I missing something?
Check you use meta data in Manifest file like that..
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="#string/google_maps_key" />
I have successfully implemented Android App links with My Local APK and it works. When I published the same APK in Google Play Store I figured out that I need to change SHA 256 fingerprint in my /.well-known/assetlinks.json with the fingerprint provided by Google. So I changed it. Unfortunately it seems that Google keeps the old copy of assetlinks.json which brakes my app links.
I have checked
https://developers.google.com/digital-asset-links/tools/generator and it said
"No app deep linking permission found for [your-app]"
I have checked
https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=[my-site]&relation=delegate_permission/common.handle_all_urls and it shows me the old version of assetlinks.json
My robots.txt
User-agent: *
Disallow:
My .htaccess file in directory /.well-known
Require all granted
RewriteEngine Off
<FilesMatch "\.(txt)$">
Require all granted
</FilesMatch>
<FilesMatch "\.(txt)$">
Allow from all
</FilesMatch>
My assetlinks.json
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target" : { "namespace": "android_app", "package_name": "my-app-id",
"sha256_cert_fingerprints": ["my-sha-256-provided-by-gogole-play-console"] }
}]
The result of https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=[my-site]&relation=delegate_permission/common.handle_all_urls
{
"statements": [
{
"source": {
"web": {
"site": "https://my-host."
}
},
"relation": "delegate_permission/common.handle_all_urls",
"target": {
"androidApp": {
"packageName": "my-app-id",
"certificate": {
"sha256Fingerprint": "the-old-sha-256-fingerprint"
}
}
}
}
],
"maxAge": "534347.929731888s",
"debugString": "********************* ERRORS *********************\nNone!\n********************* INFO MESSAGES *********************\n* Info: The following statements were considered when processing the request:\n\n---\nSource: Web asset with site https://my-host. (which is equivalent to 'https://my-host')\nRelation: delegate_permission/common.handle_all_urls\nTarget: Android app asset with package name my-app-id and certificate fingerprint the-old-sha-256 \nWhere this statement came from:\n Origin of the statement: Web asset with site https://my-host. (which is equivalent to 'https://my-host')\n Include directives followed (in order):\n \u003cNone\u003e\nMatches source query: Yes\nMatches relation query: Yes\nMatches target query: Yes\n\n--- End of statement list. ---\n\n\n"
}
The the-old-sha-256 is different from the SHA 256 in my actual assetlinks.json
P.S. my-app-id, my-host, [my-site] and so on are placeholders.
So... How to force Google to read my current assetlinks.json instead of using old cached version?
In your case, google cached your SHA256 and will take max limit
of eight days to update your SHA256. Just change the name of website
in the url given below, that will show you the SHA256 key google has
been cached.
https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://www.your-website-name.com&relation=delegate_permission/common.handle_all_urls
The assetlinks.json file may also be cached by Play Services on your
device and also on Google’s servers, so it may take a few days for
them to be updated from any changes you make to your web servers. And
SmartLock chrome/app login sharing needs your APK to be downloaded
from Google’s app store.