Overview
This guide describes how to use Secure Storage Manager (SSM) for secure deployment of files for configuring Zebra apps and/or sharing data. Files can be deployed for use by other apps (or by the originating app itself) either through Zebra OEMConfig and StageNow, a company's own EMM or programmatically from within an application.
Requirements
- Zebra device(s) running Android 11 (or later)
- Zebra MX 11.3 (or later) on device (Which version is present?)
- A staging tool (e.g. OEMConfig, StageNow, EMM, etc.)
Process Summary
- Create a Profile (in OEMConfig, StageNow, EMM, etc.) that deploys a file.
- Set the Profile to deploy using File Manager "Deploy a file for an application" File Action (requires MX 11.3 or later).
- Enter the Target Application File Definition from the Zebra App Deployment Files table (below) corresponding to the file Source* app.
- Enter the name of the signature file for the Source app (optional for StageNow deployment)
Zebra recommends this step for added security. Learn more. - For Source Access Method: Select "File in the Device File System"
- For Select Media type on a local Device: select "Others"
- For Enter File Name: Enter the Source Path and File Name_†_ from the Zebra App Deployment Files table (below)
* The "Source" app is the Zebra app that's originating the file for sharing with others. Note that the Source app can be the same app as the one consuming the shared file, such as with many app-config files.
† Where appropriate, replace the example file name with the chosen file name.
Also See
- SSM and DataWedge | Secure deployment of files for DataWedge configuration and Profiles
- SSM and WorkStation Connect | Secure deployment of files for Zebra Workstation Connect configuration and shortcuts
Deploy via Application
This section describes how to use SSM to securely deploy a file to a device. A DataWedge Profile is used as an example.
In the app's AndroidManifest.xml
file:
Add the following permissions:
<uses-permission android:name="com.zebra.securestoragemanager.securecontentprovider.PERMISSION.WRITE" /> <uses-permission android:name="com.zebra.securestoragemanager.securecontentprovider.PERMISSION.READ" />
Add the following queries to allow the app to interact with SSM:
<queries> <package android:name="com.zebra.securestoragemanager" /> <provider android:authorities="com.zebra.securestoragemanager.securecontentprovider"/> </queries>
Add the following code to define a FileProvider that allows the app to grant read permissions to files. Replace
com.app.package.name
with the package name of the app.<provider android:name="androidx.core.content.FileProvider" android:authorities="com.your.package.name.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/> </provider>
In the app's project:
In the "xml" subfolder under the "res" parent folder, add a file named
provider_paths.xml
with the following content:<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <root-path path="/data/tmp/public" name="public"/> <root-path path="/enterprise/usr" name="user"/> <external-path path="." name="external_files"/> <files-path path="." name="template"/> </paths>
Create a directory (e.g. ConfigDBs) inside the "assets" folder and copy the DataWedge Profile and/or config file within this folder:
In the app, add a function called
uploadTemplates()
, which copies files from the "assets" directory and uploads them via the copy functioncopyFileViaSSM()
.public void uploadConfigDB(boolean isFullDB) {
} private void integrateFile(AssetManager assetManager, String filename) { InputStream in = null; OutputStream out = null;AssetManager assetManager = getAssets(); String[] files = null; try { files = assetManager.list(ASSET_DB_DIR); } catch (IOException e) { Log.e(TAG, "Failed to get asset file list: " + e.getMessage()); } if (files != null) { for (String filename : files) { if (isFullDB && filename.equals("datawedge.db")) { integrateFile(assetManager, filename); } else if (!isFullDB && filename.startsWith("dwprofile_")) { integrateFile(assetManager, filename); } } } else { Log.d(TAG, "asset file list is null"); }
} private void copyFile(InputStream in, OutputStream out) throws IOException { byte[] buffer = new byte[1024]; int read; while ((read = in.read(buffer)) != -1) { out.write(buffer, 0, read); } } public void copyFileViaSSM(String sourcePath, String type) {try { in = assetManager.open(ASSET_DB_DIR + "/" + filename); String outDir = getFilesDir().getAbsolutePath() + "/"; File outFile = new File(outDir, filename); out = new FileOutputStream(outFile); copyFile(in, out); in.close(); out.flush(); out.close(); copyFileViaSSM(outFile.getAbsolutePath(), "config"); } catch (IOException e) { Log.e("tag", "Failed to copy asset file: " + filename, e); }
}File file = new File(sourcePath); Uri contentUri = FileProvider.getUriForFile(this, this.getPackageName() + ".provider", file); this.getApplicationContext().grantUriPermission("com.zebra.securestoragemanager", contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION); // Needed to grant permission for SSM to read the uri Uri cpUriQuery = Uri.parse(AUTHORITY_FILE + this.getPackageName()); try { ContentValues values = new ContentValues(); values.put("target_app_package", String.format("{\"pkgs_sigs\": [{\"pkg\":\"%s\",\"sig\":\"%s\"}]}", "com.symbol.datawedge", signature)); values.put("data_name", String.valueOf(contentUri)); // Passes the content uri as a input source values.put("data_type", "3"); values.put("data_value", "com.symbol.datawedge/" + type + "/" + file.getName()); // Replace “targetPath” with the package name of the target app that is accessing the deployed file (or retrieve the app package using context.getPackageName()) followed by "/" and the full path of the file, e.g. "context.getPackageName()/A.txt" values.put("data_persist_required", false); Uri createdRow = this.getContentResolver().insert(cpUriQuery, values); Log.i(TAG, "SSM Insert File: " + createdRow.toString()); } catch (Exception e) { Log.e(TAG, "SSM Insert File - error: " + e.getMessage() + "\n\n"); }
Call the method
uploadConfigDB(boolean isFullDB)
to upload the configuration DB files from the asset folder to DataWedge.- If uploading a full configuration DB, pass "true" for the "isFullDB" parameter
- If uploading a profile DB, pass "false" for the "isFullDB" parameter
Zebra App Deployment Files
Use the values below to deploy, share or consume files between and among Zebra apps on a device.