IOS、AndroidおよびWindows PhoneをターゲットとするXamarin.Formsプロジェクトを作成したいと思います。
私のアプリは、Facebookを使用してユーザーを認証する必要があります。
各プラットフォームに個別にログインを実装する必要がありますか、それとも手動フローを使用する必要がありますか? https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.
ログインフローの実装を1つにして、すべてのプラットフォームで使用することを好みます。
Facebookログインフローの単一の実装を取得するにはどうすればよいですか?
Xamarin.Social または Xamarin.Auth のいずれかを使用できます。プラットフォームに関係なく、同じAPIを使用できます。
現時点では、これらのライブラリはまだPCLではありませんが、共有アセットプロジェクトからそれらを使用したり、インターフェイスで必要なAPIを抽象化し、DependencyService
または他のDIコンテナを挿入したりできます。
PDATE(10/24/17):この方法は数年前は大丈夫でしたが、ここで示すwebviewメソッドではなく、ネイティブUIを使用して認証を行うことを強く推奨しています。 Auth0は、さまざまなIDプロバイダーを使用して、アプリのネイティブUIログインを実現する優れた方法です。 https://auth0.com/docs/quickstart/native/xamarin
編集:最後に のサンプルをGihubに置きました
Xamarinフォーラムに回答 を投稿しました。 ここで繰り返します。
アプリの中核であるXamarin.Forms PCLプロジェクトから始めましょう。 App
クラスは次のようになります。
_namespace OAuth2Demo.XForms
{
public class App
{
static NavigationPage _NavPage;
public static Page GetMainPage ()
{
var profilePage = new ProfilePage();
_NavPage = new NavigationPage(profilePage);
return _NavPage;
}
public static bool IsLoggedIn {
get { return !string.IsNullOrWhiteSpace(_Token); }
}
static string _Token;
public static string Token {
get { return _Token; }
}
public static void SaveToken(string token)
{
_Token = token;
}
public static Action SuccessfulLoginAction
{
get {
return new Action (() => {
_NavPage.Navigation.PopModalAsync();
});
}
}
}
}
_
最初に気づくのは、GetMainPage()
メソッドです。これにより、起動時に最初に読み込む画面をアプリに指示します。
また、認証サービスから返されるToken
を格納するための単純なプロパティとメソッド、および単純なIsLoggedIn
プロパティもあります。
Actionプロパティもあります。プラットフォーム実装がXamarin.Formsナビゲーションアクションを実行する方法を提供するために、ここにこだわっています。これについては後で詳しく説明します。
IDEにも赤が表示されます。これは、ProfilePage
クラスをまだ作成していないためです。それでは、そうしましょう。
Xamarin.Forms PCLプロジェクトに非常に単純なProfilePage
クラスを作成します。それはあなたの特定のニーズに依存するので、私たちはそれで派手なことをするつもりはありません。このサンプルの単純化のために、単一のラベルが含まれます。
_namespace OAuth2Demo.XForms
{
public class ProfilePage : BaseContentPage
{
public ProfilePage ()
{
Content = new Label () {
Text = "Profile Page",
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
}
}
}
_
繰り返しますが、おそらくIDEには赤があります。BaseContentPage
クラスがないためです。 BaseContentPage
クラスの唯一の目的は、ユーザーがログインするまでアプリの画面が表示されないようにすることです。(この単純化されたデモでは、ユーザーを永続化するだけです。情報をメモリに保存するため、アプリを実行するたびに再ログインする必要があります。実際のアプリでは、認証されたユーザー情報をデバイスのキーチェーンに保存するため、それぞれにログインする必要がなくなります。アプリの開始。)
Xamarin.Forms PCLプロジェクトでBaseContentPage
クラスを作成します。
_namespace OAuth2Demo.XForms
{
public class BaseContentPage : ContentPage
{
protected override void OnAppearing ()
{
base.OnAppearing ();
if (!App.IsLoggedIn) {
Navigation.PushModalAsync(new LoginPage());
}
}
}
}
_
ここでいくつか興味深いことがあります:
IOS UIViewControllerのViewWillAppearメソッドに似ているOnAppearing()
メソッドをオーバーライドしています。画面が表示される直前に実行したい任意のコードをここで実行できます。
このメソッドで行う唯一のことは、ユーザーがログインしているかどうかを確認することです。ログインしていない場合は、LoginPage
というクラスにmodal Pushを実行します。モーダルの概念に慣れていない場合、それは単に特別なタスクを実行するためにユーザーを通常のアプリケーションフローから外すビューです。この例では、ログインを実行します。
そこで、Xamarin.Forms PCLプロジェクトにLoginPage
クラスを作成しましょう。
_namespace OAuth2Demo.XForms
{
public class LoginPage : ContentPage
{
}
}
_
待ってください...なぜこのクラスには体がないのですか?
Xamatin.Authコンポーネント(提供されたOAuth2情報で動作するWebビューを作成および表示するジョブを実行する)を使用しているため、実際にはLoginPage
クラスでの実装は必要ありません。 。私はそれが奇妙に見えることを知っていますが、私と一緒に耐えてください。
この時点まで、私たちはXamarin.Forms PCLプロジェクトのみで作業してきました。しかし、今ではiOSプロジェクトでLoginPage
のプラットフォーム固有の実装を提供する必要があります。これがRendererの概念の出番です。
Xamarin.Formsで、プラットフォーム固有の画面とコントロール(Xamarin.Forms PCLプロジェクトの抽象ページからコンテンツを派生させない画面)を提供する場合、Renderers 。
iOSプラットフォームプロジェクトでLoginPageRenderer
クラスを作成します。
_[Assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]
namespace OAuth2Demo.XForms.iOS
{
public class LoginPageRenderer : PageRenderer
{
public override void ViewDidAppear (bool animated)
{
base.ViewDidAppear (animated);
var auth = new OAuth2Authenticator (
clientId: "", // your OAuth2 client id
scope: "", // the scopes for the particular API you're accessing, delimited by "+" symbols
authorizeUrl: new Uri (""), // the auth URL for the service
redirectUrl: new Uri ("")); // the redirect URL for the service
auth.Completed += (sender, eventArgs) => {
// We presented the UI, so it's up to us to dimiss it on iOS.
App.SuccessfulLoginAction.Invoke();
if (eventArgs.IsAuthenticated) {
// Use eventArgs.Account to do wonderful things
App.SaveToken(eventArgs.Account.Properties["access_token"]);
} else {
// The user cancelled
}
};
PresentViewController (auth.GetUI (), true, null);
}
}
}
}
_
注意すべき重要なことがあります:
最上部の[Assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]
行(および重要なことにbefore名前空間宣言)はXamarin.Forms DependencyService を使用しています。 IoC/DIではなく、それが機能するため、世界で最も美しいものではありません。これは、LoginPageRenderer
をLoginPage
に「マッピング」するメカニズムです。
これは、実際にXamarin.Authコンポーネントを使用しているクラスです。 _OAuth2Authenticator
_参照はここから来ます。
ログインが成功すると、App.SuccessfulLoginAction.Invoke();
を介してXamarin.Formsナビゲーションを開始します。これで、ProfilePage
に戻ります。
IOSを使用しているので、ViewDidAppear()
メソッドのすべてのロジックを実行しています。
AndroidプラットフォームプロジェクトでLoginPageRenderer
クラスを作成します。 (作成しているクラス名はiOSプロジェクトのものと同じですが、ここではAndroidプロジェクトではPageRendererがAndroidクラスから継承します。 iOSクラスの).
_[Assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]
namespace OAuth2Demo.XForms.Android
{
public class LoginPageRenderer : PageRenderer
{
protected override void OnModelChanged (VisualElement oldModel, VisualElement newModel)
{
base.OnModelChanged (oldModel, newModel);
// this is a ViewGroup - so should be able to load an AXML file and FindView<>
var activity = this.Context as Activity;
var auth = new OAuth2Authenticator (
clientId: "", // your OAuth2 client id
scope: "", // the scopes for the particular API you're accessing, delimited by "+" symbols
authorizeUrl: new Uri (""), // the auth URL for the service
redirectUrl: new Uri ("")); // the redirect URL for the service
auth.Completed += (sender, eventArgs) => {
if (eventArgs.IsAuthenticated) {
App.SuccessfulLoginAction.Invoke();
// Use eventArgs.Account to do wonderful things
App.SaveToken(eventArgs.Account.Properties["access_token"]);
} else {
// The user cancelled
}
};
activity.StartActivity (auth.GetUI(activity));
}
}
}
_
繰り返しますが、いくつかの興味深いことを見てみましょう。
最上部の[Assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]
行(および重要なことにbefore名前空間宣言)はXamarin.Forms DependencyService を使用しています。 iOSバージョンのLoginPageRenderer
と違いはありません。
繰り返しますが、ここで実際にXamarin.Authコンポーネントを使用しています。それが_OAuth2Authenticator
_参照の由来です。
IOSバージョンと同様に、ログインが成功すると、App.SuccessfulLoginAction.Invoke();
を介してXamarin.Formsナビゲーションを開始します。これで、ProfilePage
に戻ります。
IOSバージョンとは異なり、OnModelChanged()
ではなくViewDidAppear()
メソッド内ですべてのロジックを実行しています。
これはiOSにあります:
...およびAndroid:
PDATE:ブログでも詳細なサンプルを提供しました: http://www.joesauve.com/using-xamarin-auth-with-xamarin-forms/
ここで提案するソリューションのようなWebビューではなく、ネイティブFacebookコンポーネントを使用してFacebookログインを作成する方法を示すサンプルプロジェクトを作成しました。次のアドレスで確認できます。
IOS 8: @NovaJoeコードを使用していて表示が停止している場合は、次のコードを回避策に追加します。
bool hasShown;
public override void ViewDidAppear(bool animated)
{
if (!hasShown)
{
hasShown = true;
// the rest of @novaJoe code
}
}
良いXamarin.Forms認証サンプルを次に示します。コード内のドキュメントは素晴らしいです。 WebViewを使用してログイン画面をレンダリングしますが、必要なログインタイプを選択できます。また、ユーザートークンも保存されるため、再ログインを続ける必要はありません。
Facebookを使用するiOS8での@NovaJoeのコードへのもう1つの追加として、認証が成功した後にビューを閉じるには、以下のようにRendererクラスを変更する必要があります。
auth.Completed += (sender, eventArgs) => {
// We presented the UI, so it's up to us to dimiss it on iOS.
/ *インポートしてこの行を追加します* /
DismissViewController (true, null);
/ * * /
if (eventArgs.IsAuthenticated) {
App.Instance.SuccessfulLoginAction.Invoke ();
// Use eventArgs.Account to do wonderful things
App.Instance.SaveToken (eventArgs.Account.Properties ["access_token"]);
} else {
// The user cancelled
}
};
Androids PageRendererの正しい実装は次のとおりです。
using System;
using Android.App;
using Android.Content;
using OAuth2Demo.XForms.Android;
using Xamarin.Auth;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using XamarinAuth;
[Assembly: ExportRenderer(typeof(LoginPage), typeof(LoginPageRenderer))]
namespace OAuth2Demo.XForms.Android
{
public class LoginPageRenderer : PageRenderer
{
public LoginPageRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
// this is a ViewGroup - so should be able to load an AXML file and FindView<>
var activity = this.Context as Activity;
var auth = new OAuth2Authenticator(
clientId: "<Constants.clientId>", // your OAuth2 client id
scope: "<Constants.scope>", // the scopes for the particular API you're accessing, delimited by "+" symbols
authorizeUrl: new Uri("<Constants.authorizeUrl>"), // the auth URL for the service
redirectUrl: new Uri("<Constants.redirectUrl>")); // the redirect URL for the service
auth.Completed += (sender, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
App.SuccessfulLoginAction.Invoke();
// Use eventArgs.Account to do wonderful things
App.SaveToken(eventArgs.Account.Properties["access_token"]);
}
else
{
// The user cancelled
}
};
activity.StartActivity(auth.GetUI(activity));
}
}
}