Using .NET Google API client library with MAUI

Yoshihiro Tanaka
2 min readFeb 19, 2023

--

Google API Client Library for .NET can use with MAUI (or Xamarin), but it throws NotSupportedException when used on iOS and Android. I guess there are some solutions to resolve it. I’ll introduce 1 solution among them. Note that this solution is implemented for Android and iOS apps. Custom URI schemes are also available for MacOS and Windows apps, but I haven’t tried them.

tl;dr

Implement ICodeReceiver, and pass it to GoogleWebAuthorizationBroker via AuthorizeAsync.

Procedure

Implement the code receiver

The default code receiver LocalServerCodeReceiver does not support native applications. This is the root of the problem, so let’s implement it instead of the default one.

class CodeReceiver : ICodeReceiver
{
public string RedirectUri => "";

public async Task<AuthorizationCodeResponseUrl> ReceiveCodeAsync(AuthorizationCodeRequestUrl url,
CancellationToken taskCancellationToken)
{
throw new NotImplementedException();
}
}

Open the browser using Launcher.

public async Task<AuthorizationCodeResponseUrl> ReceiveCodeAsync(AuthorizationCodeRequestUrl url,
CancellationToken taskCancellationToken)
{
await Launcher.Default.OpenAsync(url.Build().AbsoluteUri);
}

Define a custom URI scheme

Next, we need to handle the result. For that, let’s prepare a custom URI scheme. Update the Info.plist and MainActivity to define a custom URI scheme.

For iOS, open Info.plist in Visual Studio or your editor and add CFBundleURLTypes directly.

For Android, I guess the IntentFilter attribute is better than the XML tag.

A custom URI scheme must start with the package name, and be separated by “:” instead of “://”. For instance, “com.example.foo:oauth2/redirect”. Please check the official documentation for more information.

class CodeReceiver : ICodeReceiver
{
public string RedirectUri => "com.example.foo:oauth2/redirect";

// ...
}

Receive the result

The app will receive the result from OnCreate on Android and OpenUrl on iOS. We need to receive it and notify ICodeReceiver of the result using TaskCompletionSource etc. If you need an example, please check my repository at the bottom.

public class MainActivity : MauiAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
var rawUri = Intent?.Data?.ToString();
FooNotifier.Notify(rawUri);
}
}
public class AppDelegate : MauiUIApplicationDelegate
{
public override bool OpenUrl(UIApplication application, NSUrl url, NSDictionary options)
{
var rawUri = url.AbsoluteString;
FooNotifier.Notify(rawUri);
return true;
}
}

Return the authorization information

As you know, returned URL contains the necessary information for authorization. Parse the query after verifying the returned URL.

public async Task<AuthorizationCodeResponseUrl> ReceiveCodeAsync(AuthorizationCodeRequestUrl url,
CancellationToken taskCancellationToken)
{
await Launcher.Default.OpenAsync(url.Build().AbsoluteUri);
var rawUri = await FooNotifier.WaitForResponse;
var uri = new Uri(rawUri);

// ...

var query = HttpUtility.ParseQueryString(uri.Query);
return new AuthorizationCodeResponseUrl
{
Code = query.Get("code"),
State = query.Get("state"),
Error = query.Get("error"),
ErrorDescription = query.Get("error_description"),
ErrorUri = query.Get("error_uri")
};
}

Set the code receiver

Let’s set the code receiver to Broker.

var credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
clientSecrets,
scopes,
"user",
CancellationToken.None,
codeReceiver: new CodeReceiver()
);

// ...

You will be able to use the credential like the default implementation!

👋

Example

--

--