Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] exported="true" when MauiLauncher=true (#…
Browse files Browse the repository at this point in the history
…6212)

Fixes: #6196

Context: https://aster.cloud/2021/02/23/lets-be-explicit-about-our-intent-filters/

> An important change is coming to Android 12 that improves both app
> and platform security. This change affects all apps that target
> Android 12.
>
> Activities, services, and broadcast receivers with declared
> intent-filters now must explicitly declare whether they should be
> exported or not.

For example:

	<activity android:icon="@mipmap/icon" android:label="HelloWorld" android:name="example.MainActivity">
	  <intent-filter>
	    <action android:name="android.intent.action.MAIN" />
	    <category android:name="android.intent.category.LAUNCHER" />
	  </intent-filter>
	</activity>

Should become:

	<activity android:exported="true" android:icon="@mipmap/icon" android:label="HelloWorld" android:name="example.MainActivity">
	  <intent-filter>
	    <action android:name="android.intent.action.MAIN" />
	    <category android:name="android.intent.category.LAUNCHER" />
	  </intent-filter>
	</activity>

Update our `AndroidManifest.xml` generation & related code so that
when `MainLauncher=true`, we also automatically set `exported=true`.

I updated a test to verify the contents of the generated
`AndroidManifest.xml`.
  • Loading branch information
jonathanpeppers authored Aug 21, 2021
1 parent 8f54f27 commit d304060
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,31 @@ public void CheckElementReOrdering ([Values (true, false)] bool useAapt2)
var manifestFile = Path.Combine (Root, builder.ProjectDirectory, proj.IntermediateOutputPath, "android", "AndroidManifest.xml");
XDocument doc = XDocument.Load (manifestFile);
var ns = doc.Root.GetNamespaceOfPrefix ("android");
var manifest = doc.Element ("manifest");
Assert.IsNotNull (manifest, "manifest element should not be null.");
var app = manifest.Element ("application");
Assert.IsNotNull (app, "application element should not be null.");
var manifest = GetElement (doc, "manifest");
var app = GetElement (manifest, "application");
Assert.AreEqual (0, app.ElementsAfterSelf ().Count (),
"There should be no elements after the application element");
var activity = GetElement (app, "activity");
AssertAttribute (activity, ns + "exported", "true");
var intent_filter = GetElement (activity, "intent-filter");
var action = GetElement (intent_filter, "action");
AssertAttribute (action, ns + "name", "android.intent.action.MAIN");
var category = GetElement (intent_filter, "category");
AssertAttribute (category, ns + "name", "android.intent.category.LAUNCHER");
}

static XElement GetElement (XContainer parent, XName name)
{
var e = parent.Element (name);
Assert.IsNotNull (e, $"{name} element should not be null.");
return e;
}

static void AssertAttribute (XElement parent, XName name, string expected)
{
var a = parent.Attribute (name);
Assert.IsNotNull (a, $"{name} attribute should not be null.");
Assert.AreEqual (expected, a.Value, $"{name} attribute value did not match.");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,7 @@ void AddLauncherIntentElements (XElement activity)
return;

var filter = new XElement ("intent-filter");
activity.Add (new XAttribute (androidNs + "exported", "true"));
activity.AddFirst (filter);
foreach (KeyValuePair<string, string> e in LauncherIntentElements) {
if (!filter.Elements (e.Key).Any (x => ((string) x.Attribute (attName)) == e.Value))
Expand Down

0 comments on commit d304060

Please sign in to comment.