fc2ブログ

記事一覧

Android 12 (S) API 31 への対応方法 | Xamarin.Forms


今回は 期限が2022年11月1日に差し迫った、アプリをターゲットフレームワーク Android 12 S (API 31) へ対応する方法につきまして、覚え書きしたいと思います。
ただし、当初からビルドエラーに苦しむなど、対応方法の難易度が高いことで重い腰が動きませんでした。しかしながら、Google Billing Client の対応等が必須で、重い腰を動かさざるを得ない状況でしたので、調査しながら対応したのですが、最新の Visual Studio 2022 のバージョン 17.3.6 だと発生し、少し古いバージョン17.1.6だとエラーにならないことが多くあり、苦労しました。
また、以下の Google のサイトにも Android 12 への対応方法が記載されていますが、Xamarin 特有のエラーなどはもちろん記載されておらず、Xamarin に関する調査が必要でした。

【Google 公式サイトの内容】
https://developer.android.com/about/versions/12/behavior-changes-12?hl=ja
https://developer.android.com/about/versions/12/behavior-changes-all?hl=ja



前提条件
・Windows10 Pro 64Bit 1903
・Visual Studio 2022 Community v17.3.6
・Xamarin 17.3.0.308 (NuGet Xamarin.Forms 4.6.0.1141)



1.事前準備

Android12 の SDK やシミュレータをインストールするために、Visual Studio 2022 のバージョンを v17.3.6 以降に更新します。

更新したら、Android SDK マネージャで、Android 12 の必要な環境をダウンロード & インストールします。

Android12_01_SDK.png


その上で、Android プロジェクトのプロパティからターゲットフレームワークを Android 12.0 (S) に変更します。

Android12_02_TargetFramework.png



2.values.xml のエラー

ターゲットフレームワークを Android 12 (S) に変更してビルドすると、ビルドエラーになる場合があります。もちろん クリーン&リビルド や .vs / bin / obj フォルダを削除しても効果が無く、再現性もないエラーでしたが、ネットには数多く事例がありましたので、ここに記載しておきます。対応方法はわかったのですが、根本原因につきまして何かお分かりになる方がいらっしゃいましたら、コメント頂ければ幸いです。

【エラー内容】
Error parsing XML: no element found
XML ドキュメントには、ルート レベルの要素が含まれている必要があります。
その他のファイル obj\Debug\120\lp\116\jl\res\values\values.xml


Android12_03_values_xml_error.png


【対応方法】
インクリメンタル Android パッケージシステム (aapt2)  を使用することで回避が可能です。ただし、一度チェックをONにしてビルドして、OFFにしてビルドしても再度エラーが出ることは無くなります。(この点がよくわからないポイントです。)

Android12_04_aapt2.png



3.必須の exported 属性

Android 12 (S) 以降からは、 Activity に exported の設定が必須となっているようです。対策せずにビルドすると、以下のようなエラーが発生します。

【エラー内容】
android:exported needs to be explicitly specified for element <activity#com.CompanyName.MainActivity>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See
https://developer.android.com/guide/topics/manifest/activity-element#exported for details.


【対応方法】
Activityを継承しているクラスに Exported = true または false の設定を追加します。Google のサイトには AndroidManifest.xml に追加するように記載されていますが、Xamarin はビルド後に AndroidManifest.xml に追加されますので、実装クラスの方に追記します。他にも、通知や BootReciever に使用している BroadCastReciever 等のクラスにも追加が必要です。

MainActivity.cs
[Activity(Label = "AppName", Icon = "@drawable/icon", Theme = "@style/MyTheme",
Name = "com.CompanyName.AppName.MainActivity",
Exported = true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{


Android12_05_exported_true.png



4.スプラッシュスクリーンの対応

次の記事「Android 12 (S) の新しいスプラッシュスクリーンに対応する方法」をご参考ください。



5.DEX エラーの対応方法

さらにビルドすると、DEXのエラーに遭遇することがあります。

【エラー内容】
Using the DX DEX Compiler is not supported. Please set the DEX compiler to 'd8' in the Visual Studio project property pages or edit the project file in a text editor and set the 'AndroidDexTool' MSBuild property to 'd8'.    AppName.Android   

【対応方法】
Androidプロジェクト > Android オプション から Dexコンパイラを dx から d8 に変更します。dx は従来のビルド方式となっており、d8 が新しい Android12 のビルドに対応した形式となっているようです。

Android12_07_dex.png



6.minSdkVersion の変更

Android 12 (S) のビルドでは、Android 5 API 21 以上にする必要があるようです。minSdkVersion を 21 以上にしていない場合は、ビルドエラーになりました。NuGet パッケージの Xamarin.Forms を更新するとその必要があると認識していましたが、ターゲットフレームワークのバージョンでも上げる必要があるのには驚きです。

【対応方法】
Androidプロジェクト > Android マニフェスト から 最小 Android バージョンを 21 以上に設定します。

Android12_08_minversion.png



7.PendingIntent の必須要件

SDK31 でビルドしたアプリを実行すると、実行時に PendingIntent のエラーが発生するようになります。これは、 Android 12 以降で PendingIntentFlags.Mutable または PendingIntentFlags.Immutable を渡すことが必須となっているようですので、ソースコードの変更が必要でした。
詳細は以下のURLに記載があります。
https://developer.android.com/reference/android/app/PendingIntent

【対応方法】
PendingIntent.GetActivity や PendingIntent.GetBroadcast 等で PendingIntent を取得するメソッドに渡す引数に PendingIntentFlags がありますが、その値を PendingIntentFlags.Mutable または PendingIntentFlags.Immutable に変更します。しかしながら、従来のAndroid バージョンでの実装と異なる結果となりますので、Android12 以降での条件分岐が必要となります。そこで私の場合はラッパークラスを実装して、置き換えることにより対応します。

PendingIntentWrapper.cs
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Context = Android.Content.Context;

namespace AppName.Droid.Models
{
public static class PendingIntentWrapper
{
/// <summary>
/// PendingIntentを取得する(Android12対応)
/// </summary>
/// <param name="context"></param>
/// <param name="requestCode"></param>
/// <param name="intent"></param>
/// <param name="flags"></param>
/// <returns></returns>
public static PendingIntent GetBroadcast(Context context, int requestCode, Intent intent, [GeneratedEnum] PendingIntentFlags flags)
{
flags = PendingIntentWrapper.GetFlags(flags);
return PendingIntent.GetBroadcast(context, requestCode, intent, flags);
}

/// <summary>
/// PendingIntentを取得する(Android12対応)
/// </summary>
/// <param name="context"></param>
/// <param name="requestCode"></param>
/// <param name="intent"></param>
/// <param name="flags"></param>
/// <returns></returns>
public static PendingIntent GetActivity(Context context, int requestCode, Intent intent, [GeneratedEnum] PendingIntentFlags flags)
{
flags = PendingIntentWrapper.GetFlags(flags);
return PendingIntent.GetActivity(context, requestCode, intent, flags);
}

/// <summary>
/// PendingIntentFlagsの変換(Android12対応)
/// </summary>
/// <param name="flags">PendingIntentFlags</param>
/// <returns></returns>
private static PendingIntentFlags GetFlags(PendingIntentFlags flags)
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.S)
{
if (flags == PendingIntentFlags.Immutable ||
flags == PendingIntentFlags.Mutable)
{
return flags;
}
else if (flags == PendingIntentFlags.NoCreate ||
flags == PendingIntentFlags.CancelCurrent)
{
return flags | PendingIntentFlags.Immutable;
}
//PendingIntentFlags.OneShot
//PendingIntentFlags.UpdateCurrent
return flags | PendingIntentFlags.Mutable;
}
return flags;
}
}
}

※ 上記の PendingIntentWrapper で PendingIntent.Get*** を置き換えて動作を確認します。
※2023/02/04追記
フラグの併用が可能なことが分かり、既存の設定したフラグに Mutable または Immutable を OR 条件として付加するように修正しました。



8.通知の仕様変更について

Android 12 (S) 以降では、アプリからシステムダイアログ(画面上からスワイプして降りてくるアレです)を閉じれなくなりました。通知のボタンを押した際に、今まではダイアログを閉じてアプリを起動するなどの対応が必要でしたが、Android 12 (S) 以降ではOSがダイアログを自動的に閉じてくれるため、アプリ側の処理が必要なくなります。さらには、BroadcastReceiver から StartActivity を実行することができなくなっていました。詳しくは、以前の記事「Androidの通知にアクションボタンを表示して処理を分岐する方法」をご参考ください。

※2023/02/04追記
上記リンクにつきまして、ローカル通知にボタンを表示して、そのボタンからアプリを起動する際のロジックを変更しました。



9.その他の対応

また、必須ではないかもしれませんが、
Xamarin.Build.Download が必要なくなったため、アンインストールしました。
 ※Xamarin.Build.Download は Xamarin.GooglePlayServices 関連で必要なものでしたので、改めてインストールしました。
・Admob も対応が必要の様ですが、Android13 以降からの対応となるようなので、今回はスルーします。
Xamarin.Android.Google.BillingClient V3 は V4 に更新しましたが、ソースコードの変更は必要ありませんでした。
・トーストに関しては、アプリを更新してすぐではアプリアイコンが表示されなかったのですが、Android OS 再起動後に正常に表示されるようになりました。(トーストに関しては文字数の長ささえ気にしていればその他の対応は必要ないと思います。)

その他、判明した内容は随時追記していきます。


以上で、ターゲットフレームワーク Android 12 S に対応したアプリの公開ができました。

※2022/11/09追記
通知からシステムダイアログを閉じる処理について Android12 での変更点を確認し、対応方法がわかりましたので、記事を追記しました。






最後までお読みいただきありがとうございます。
当ブログの内容をまとめた Xamarin逆引きメニュー は以下のURLからご覧になれます。
https://itblog.dynaspo.com/blog-entry-81.html


関連記事

コメント

コメントの投稿

※名前とタイトルが入力されていないコメントでは他のコメントとの区別ができません。

 入力されていないコメントには返信しませんのであらかじめご了承くださいませ。

※ニックネームでも良いので必ずご入力ください。

    

※必ずご入力ください。

    
    

※必ずご入力ください。

※技術的な質問には環境やエラーについて正確かつ詳細にお教えください。

・正確なエラーの内容

・Windowsのバージョン番号

・Visual Studioのバージョン

・機器の型番

・アプリやソフトのバージョン

    

カテゴリ別記事一覧

広告

プロフィール

石河 純


著者名 :石河 純
自己紹介:素人上がりのIT技術者。趣味は卓球・車・ボウリング

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Catalina 10.15 / Mojave 10.14 / High Sierra 10.13 / Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
【データベース】
Oracle 10g/9i
SQLServer 2016/2008R2/2005/2000
SQLAnywhere 16/11/8
【BI/レポートツール】
Cognos ReportNet (IBM)
Microsoft PowerBI
ActiveReport (GrapeCity)
CrystalReport
【OCX関連】
GrapeCity InputMan SPREAD MultiRow GridView
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS jQuery IIS6/7 apache2

休みの日は卓球をやっています。
現在、卓球用品通販ショップは休業中です。