Microsoft Intune App SDK for Android developer guide
The Microsoft Intune App SDK for Android lets you incorporate Intune app protection policies (also known as APP or MAM policies) into your native Java/Kotlin Android app. An Intune-managed application is one that is integrated with the Intune App SDK. Intune administrators can easily deploy app protection policies to your Intune-managed app when Intune actively manages the app.
Important
Intune regularly releases updates to the Intune App SDK. We recommend subscribing to the Intune App SDK repositories for updates so that you can incorporate the update into your software development release cycle and ensure your apps support the latest App Protection Policy settings.
Plan to take mandatory Intune App SDK updates prior to every major OS release to ensure your app continues to run smoothly as OS updates can cause breaking changes. If you do not update to the latest version prior to a major OS release, you may run the risk of encountering a breaking change and/or being unable to apply app protection policies to your app.
Process flow
The following diagram provides the Intune App SDK for Android process flow:
Stage Goals
The guide contains greater detail about the Intune App SDK's architecture, information about uncommon integration steps, and other helpful content.
The SDK in Greater Detail
Class and Method Replacements
Through the build tooling, the Intune App SDK attempts to minimize the integration burden of Android developers. Prior to the build tooling, developers needed to perform all replacements manually.
Note
Apps must now integrate with the SDK build tooling, which will perform all of these replacements automatically.
Android base classes are replaced with their respective MAM equivalents in order to enable Intune management.
The SDK classes live between the Android base class and the app's own derived version of that class.
For example, an app activity might end up with an inheritance hierarchy that looks like: AppSpecificActivity
extends MAMActivity
extends Activity
.
The MAM layer filters calls to system operations in order to seamlessly provide your app with a managed view of the world.
In addition to base classes, some classes your app might use without deriving from (e.g. MediaPlayer
) also have required MAM equivalents, and some method calls must also be replaced.
The table below lists many of the MAM replacements.
Android base class | Intune App SDK replacement |
---|---|
android.app.Activity | MAMActivity |
android.app.ActivityGroup | MAMActivityGroup |
android.app.AliasActivity | MAMAliasActivity |
android.app.Application | MAMApplication |
android.app.Dialog | MAMDialog |
android.app.AlertDialog.Builder | MAMAlertDialogBuilder |
android.app.DialogFragment | MAMDialogFragment |
android.app.ExpandableListActivity | MAMExpandableListActivity |
android.app.Fragment | MAMFragment |
android.app.IntentService | MAMIntentService |
android.app.LauncherActivity | MAMLauncherActivity |
android.app.ListActivity | MAMListActivity |
android.app.ListFragment | MAMListFragment |
android.app.NativeActivity | MAMNativeActivity |
android.app.PendingIntent | MAMPendingIntent |
android.app.Service | MAMService |
android.app.TabActivity | MAMTabActivity |
android.app.TaskStackBuilder | MAMTaskStackBuilder |
android.app.backup.BackupAgent | MAMBackupAgent |
android.app.backup.BackupAgentHelper | MAMBackupAgentHelper |
android.app.backup.FileBackupHelper | MAMFileBackupHelper |
android.app.backup.SharePreferencesBackupHelper | MAMSharedPreferencesBackupHelper |
android.app.job.JobService | MAMJobService |
android.content.BroadcastReceiver | MAMBroadcastReceiver |
android.content.ContentProvider | MAMContentProvider |
android.os.Binder | MAMBinder (Only necessary if the Binder is not generated from an Android Interface Definition Language (AIDL) interface) |
android.media.MediaPlayer | MAMMediaPlayer |
android.media.MediaMetadataRetriever | MAMMediaMetadataRetriever |
android.media.MediaRecorder | MAMMediaRecorder |
android.provider.DocumentsProvider | MAMDocumentsProvider |
android.preference.PreferenceActivity | MAMPreferenceActivity |
android.widget.PopupWindow | MAMPopupMenu |
android.widget.PopupWindow | MAMPopupWindow |
android.widget.ListPopupWindow | MAMListPopupWindow |
android.widget.TextView | MAMTextView |
android.widget.AutoCompleteTextView | MAMAutoCompleteTextView |
android.widget.CheckedTextView | MAMCheckedTextView |
android.widget.EditText | MAMEditText |
android.inputmethodservice.ExtractEditText | MAMExtractEditText |
android.widget.MultiAutoCompleteTextView | MAMMultiAutoCompleteTextView |
android.view.LayoutInflater | MAMLayoutInflater |
android.view.ViewGroup | MAMViewGroup |
android.view.SurfaceView | MAMSurfaceView |
android.opengl.GLSurfaceView | MAMGLSurfaceView |
android.widget.VideoView | MAMVideoView |
Renamed Methods
In many cases, a method available in the Android class has been marked as final in the MAM replacement class.
In this case, the MAM replacement class provides a similarly named method (generally suffixed with MAM
) that you should override instead.
For example, when deriving from MAMActivity, instead of overriding onCreate()
and calling super.onCreate()
, Activity
must override onMAMCreate()
and call super.onMAMCreate()
.
The Java compiler should enforce the final restrictions to prevent accidental override of the original method instead of the MAM equivalent.
Wrapped System Services
For some system service classes, it's necessary to call a static
method on a MAM wrapper class instead of directly invoking the desired
method on the service instance.
For example, a call to
getSystemService(ClipboardManager.class).getPrimaryClip()
must
become a call to
MAMClipboardManager.getPrimaryClip(getSystemService(ClipboardManager.class)
.
Again, the required build plugin automatically makes these replacements.
Android Class | Intune App SDK replacement |
---|---|
android.content.ClipboardManager | MAMClipboard |
android.content.ContentProviderClient | MAMContentProviderClientManagement |
android.content.ContentResolver | MAMContentResolverManagement |
android.content.pm.PackageManager | MAMPackageManagement |
android.app.DownloadManager | MAMDownloadManagement |
android.print.PrintManager | MAMPrintManagement |
android.view.View | MAMViewManagement |
android.view.DragEvent | MAMDragEventManagement |
android.view.LayoutInflater | MAMLayoutInflaterManagement |
android.app.NotificationManager | MAMNotificationManagement |
android.app.blob.BlobStoreManager | MAMBlobStoreManager |
android.app.blob.BlobStoreManager.Session | MAMBlobStoreManager.Session |
Some classes have most of their methods wrapped, for example, ClipboardManager
, ContentProviderClient
, ContentResolver
,
and PackageManager
while other classes have only one or two methods wrapped, for example, DownloadManager
, PrintManager
, PrintHelper
,
View
, DragEvent
, NotificationManager
and NotificationManagerCompat
.
MDM and MAM Enrollment
As discussed in Stage 4's Registration vs Enrollment, the Intune App SDK will "enroll" accounts that your app registers so that account is protected with policy. The account becomes managed after this enrollment succeeds, and MAM policies should now be applied to this account.
The term "enrollment" can also refer to the end-user initiated process for enabling Device Management (MDM). MDM enrollment is entirely separate from App Protection Policy enrollment.
An SDK-integrated app can have an account enrolled for App Protection Policy without that account being enrolled for Device Management. Likewise, a user can have enrolled a device for Device Management without having any SDK-integrated apps with accounts enrolled for App Protection Policy.
Typically, when developers and administrators refer to enrollment, they're referring to MDM enrollment, as App Protection Policy enrollment is largely invisible to both developers and end users. See Enroll Android devices for more details on MDM enrollment.
Integration Tips
Understanding Company Portal logs
Company Portal logs contain information that Microsoft engineers use for issue investigations. Some of the logs can be useful for developers integrating the SDK as well.
In particular, the file DiagnosticsInfo-scrubbed.log
contains information on what apps are managed by MAM and the MAM policy details in the PolicyDB Information
section.
Every managed app has an entry in the PolicyDB Information
section.
You should look for your app's package name here to confirm that MAM
policy is correctly targeted to your app.
If you don't see your app's package name here, it indicates that the account logged in doesn't have MAM policy applied.
For description on each MAM policy setting, refer to Android app protection policy settings in Microsoft Intune. For a description of how these settings will show up in the Company Portal logs, refer to Review client app protection logs. When MAM policy isn't being enforced as expected, we recommend that you check Company Portal logs or the diagnostic UI, verify that your app is managed by MAM policy, and confirm the policy settings have expected values.
You can collect Company Portal logs in one of the following ways:
- Through the Company Portal
- Open the Company Portal app
- Select the three dots menu on the up right corner
- Select Settings
- Under Diagnostic Logs, select Save Logs
- Follow the prompt to choose the output directory to save the Company Portal logs.
- Use
adb shell pull
command to pull the logs from your Android device to your local machine.
- [Use Microsoft Edge for Android to access managed app logs]. This will display UI for collecting Company Portal logs and viewing MAM diagnostics.
- Call
MAMPolicyManager.showDiagnostics(context)
to display the same UI for collecting Company Portal logs.
Quickly testing with changing policy
As you're developing and testing your app's integration of the Intune App SDK, you may frequently change the App Protection Policy settings for your test user.
By default, integrated apps will check in with the Intune service for updated policy every 30 minutes, when active. You can avoid this wait and force a check-in through the Company Portal:
- Launch the Company Portal. You don't need to sign in.
- Select the ... menu icon.
- Select Settings.
- Scroll to the setting called "Management Policy".
- Press the Sync button.
This will immediately schedule a check-in and will retrieve up-to-date policy targeted to your app and account.
Troubleshooting AndroidX Migration
If you integrated the Intune App SDK before leveraging AndroidX, you may encounter an error like this while migrating to AndroidX:
incompatible types: android.support.v7.app.ActionBar cannot be converted to androidx.appcompat.app.ActionBar
These errors can occur because your app references the SDK's legacy support classes. The MAM support classes wrap Android support classes that have moved in AndroidX. To combat such errors, replace all MAM support class references with their AndroidX equivalents. This can be achieved by first removing the MAM support library dependencies from your Gradle build files. The lines in question will look something like the following:
implementation "com.microsoft.intune.mam:android-sdk-support-v4:$intune_mam_version"
implementation "com.microsoft.intune.mam:android-sdk-support-v7:$intune_mam_version"
Then, fix the resulting compile-time errors by replacing all references to MAM classes in the com.microsoft.intune.mam.client.support.v7
and com.microsoft.intune.mam.client.support.v4
packages with their AndroidX equivalents.
For example, references to MAMAppCompatActivity
should be changed to AndroidX's AppCompatActivity
.
As discussed above, the MAM build plugin/tool will automatically rewrite classes in the AndroidX libraries with the appropriate MAM equivalents at compile-time.
Limitations and Special Cases
Default enrollment
Your application can alternately register for App Protection Policies through a simplified process called default enrollment. This feature is primarily to support private line-of-business apps that haven't integrated MSAL.
Warning
Default enrollment comes with significant tradeoffs and is not recommended. Apps leveraging default enrollment do not support Conditional Access, do not benefit from SSO with Microsoft services, and cannot be used by non-Intune accounts. If your app ships to a public app store, default enrollment is not supported.
Default enrollment will force the end user to install the Company Portal and complete a MAM enrollment flow before allowing users into your application.
Note
Default enrollment is sovereign cloud aware.
Enable default enrollment with the following steps:
If your app integrates MSAL or you need to enable SSO, configure MSAL. If not, you may skip this step.
Enable default enrollment by adding the following value in the manifest under the
<application>
tag:<meta-data android:name="com.microsoft.intune.mam.DefaultMAMServiceEnrollment" android:value="true" />
Enable MAM policy required by adding the following value in the manifest under the
<application>
tag:<meta-data android:name="com.microsoft.intune.mam.MAMPolicyRequired" android:value="true" />
Isolated Processes
The Intune App SDK can't apply protections to isolated processes.
Support for isolated processes (android:isolatedProcess
) requires the addition of the meta-data tag below.
Warning
By adding this meta-data, your application is declaring that the isolated process cannot expose organization data. Your application is responsible for guaranteeing this.
<meta-data android:name="com.microsoft.intune.mam.AllowIsolatedProcesses" android:value="true" />
Custom Screen Capture Restrictions
If your app contains a custom screen capture feature that bypasses Android's Window
-level FLAG_SECURE
restriction, you must check screen capture policy before allowing full access to the feature.
For example, if your app uses a custom rendering engine to render the current view to a PNG file, you must first check AppPolicy.getIsScreenCaptureAllowed()
.
If your app doesn't contain any custom or third-party screen capture features, you aren't required to take any action to restrict screen captures.
Screen capture policy is automatically enforced at the Window
level for all MAM integrated apps.
Any attempts by the OS or another app to capture a Window
in your app will be blocked as required.
For example, if a user attempts to capture your app's screen through Android's built-in screenshot or screen recording features, the capture will be automatically restricted without participation from your app.
Policy enforcement limitations
Using Content Resolvers: The "transfer or receive" Intune policy may block or partially block the use of a content resolver to access the content provider in another app. This will cause
ContentResolver
methods to return null or throw a failure value (for example,openOutputStream
will throwFileNotFoundException
if blocked). The app can determine whether a failure to write data through a content resolver was caused by policy (or would be caused by policy) by making the call:MAMPolicyManager.getPolicy(currentActivity).getIsSaveToLocationAllowed(contentURI);
or if there's no associated activity:
MAMPolicyManager.getCurrentThreadPolicy().getIsSaveToLocationAllowed(contentURI);
In this second case, multi-identity apps must take care to set the thread identity appropriately (or pass an explicit identity to a
getPolicyForIdentity
call).
Exported services
The AndroidManifest.xml file included in the Intune App SDK contains MAMNotificationReceiverService, which must be an exported service to allow the Company Portal to send notifications to a managed app. The service checks the caller to ensure that only the Company Portal is allowed to send notifications.
Reflection limitations
Some of the MAM base classes (for example, MAMActivity
, MAMDocumentsProvider
) contain methods (based on the original Android base classes) which use parameter or return types only present above certain API levels.
For this reason, it may not always be possible to use reflection to enumerate all methods of app components.
This restriction isn't limited to MAM, it's the same restriction that would apply if the app itself implemented these methods from the Android base classes.
Robolectric
Testing Intune App SDK behavior under Robolectric isn't supported. There are known issues running the SDK under Robolectric due to behaviors present under Robolectric that don't accurately mimic those on real devices or emulators.
If you need to test your application under Robolectric, the recommended workaround is to move your application class logic to a helper and produce your unit-testing apk with an application class that doesn't inherit from MAMApplication.