欢迎大家
第一:
我使用了这个示例:“https://github.com/stevenchang0529/XamarinGoogleDriveRest” 这是一个解释如何将 Google Drive API 与 XamrinForms 结合使用的项目,顺便说一下,感谢 Steven Chang。
它工作正常,但每次我想将文件上传到Google Drive时都要求登录帐户,如何才能使其在第一次输入后保存登录数据。
第二: 如何让用户从弹出窗口中选择他的帐户“如下图所示”,而不是使用 Web Authenticator Native Browser:
项目中使用的ViewModel类:
public class MainViewModel
{
private string scope = "https://www.googleapis.com/auth/drive.file";
private string clientId = "clientId here";
private string redirectUrl = "url:/oauth2redirect";
public ICommand OnGoogleDrive { get; set; }
public MainViewModel()
{
var auth = new OAuth2Authenticator(
this.clientId,
string.Empty,
scope,
new Uri("https://accounts.google.com/o/oauth2/v2/auth"),
new Uri(redirectUrl),
new Uri("https://www.googleapis.com/oauth2/v4/token"),
isUsingNativeUI: true);
AuthenticatorHelper.OAuth2Authenticator = auth;
auth.Completed +=async (sender, e) =>
{
if (e.IsAuthenticated)
{
var initializer = new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new Google.Apis.Auth.OAuth2.ClientSecrets()
{
ClientId = clientId
}
};
initializer.Scopes = new[] { scope };
initializer.DataStore = new FileDataStore("Google.Apis.Auth");
var flow = new GoogleAuthorizationCodeFlow(initializer);
var user = "DriveTest";
var token = new TokenResponse()
{
AccessToken=e.Account.Properties["access_token"],
ExpiresInSeconds=Convert.ToInt64( e.Account.Properties["expires_in"]),
RefreshToken=e.Account.Properties["refresh_token"],
Scope=e.Account.Properties["scope"],
TokenType=e.Account.Properties["token_type"]
};
UserCredential userCredential = new UserCredential(flow, user, token);
var driveService = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = userCredential,
ApplicationName = "Quickstart",
});
//test google drive
DriveServiceHelper helper = new DriveServiceHelper(driveService);
var id = await helper.CreateFile();
await helper.SaveFile(id, "test", "test save content");
var content = await helper.ReadFile(id);
}
};
auth.Error += (sender, e) =>
{
};
this.OnGoogleDrive = new Command(() =>
{
var presenter = new OAuthLoginPresenter();
presenter.Login(auth);
});
}
}
public static class AuthenticatorHelper
{
public static OAuth2Authenticator OAuth2Authenticator { get; set; }
}
即使使用 Xamarin Forms,它也不会 100% 像您在 iOS 设备上的图像。我认为这是一种让 iOS 和 Android 平台都变得相似的方法。
这是一些示例代码。
共享
主页.xaml
此按钮仅在用户未登录时可见。
...
<Button Text="Google Login"
Command="{Binding GoogleLoginCommand}"
IsVisible="{Binding IsLogedIn, Converter={StaticResource InvertBooleanConverter}}"/>
...
InvertBooleanConverter.cs 当 IsLogedIn 为 True 时,此转换器返回 false;当 IsLogedIn 为 false 时,此转换器返回 true。
public class InvertBooleanConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return !(bool)value;
}
}
型号 GoogleUser.cs
public class GoogleUser
{
public string Name { get; set; }
public string Email { get; set; }
public Uri Picture { get; set; }
}
视图模型
...
public class MainPageViewModel {
private readonly IGoogleManager _googleManager;
public DelegateCommand GoogleLoginCommand { get; set; }
private bool _isLogedIn;
public bool IsLogedIn
{
get { return _isLogedIn; }
set { _isLogedIn = value; }
}
private GoogleUser _googleUser;
public GoogleUser GoogleUser
{
get { return _googleUser; }
set { _googleUser = value; }
}
...
public MainPageViewModel(IGoogleManager googleManager){ //Without IoC
_googleManager = googleManager;
IsLogedIn = false;
GoogleLoginCommand = new DelegateCommand(GoogleLogin);
}
private void GoogleLogin()
{
_googleManager.Login(OnLoginComplete);
}
private void OnLoginComplete(GoogleUser googleUser, string message)
{
if (googleUser != null){
GoogleUser = googleUser;
IsLogedIn = true;
//Your code after login
} else {
//Error
}
}
...
每个设备的接口
public interface IGoogleManager
{
void Login(Action<GoogleUser, string> OnLoginComplete);
void Logout();
}
iOS
您的项目名称.ios
AppDelegate.cs 将此代码添加到 AppDelegate 类
...
var googleServiceDictionary = NSDictionary.FromFile("GoogleService-Info.plist");
SignIn.SharedInstance.ClientID = googleServiceDictionary["CLIENT_ID"].ToString();
...
GoogleManager.cs
public class GoogleManager : NSObject, IGoogleManager, ISignInDelegate, ISignInUIDelegate
{
private Action<GoogleNativeLogin.Models.GoogleUser, string> _onLoginComplete;
private UIViewController _viewController { get; set; }
public GoogleManager()
{
SignIn.SharedInstance.UIDelegate = this;
SignIn.SharedInstance.Delegate = this;
}
public void Login(Action<GoogleNativeLogin.Models.GoogleUser, string> OnLoginComplete)
{
_onLoginComplete = OnLoginComplete;
var window = UIApplication.SharedApplication.KeyWindow;
var vc = window.RootViewController;
while (vc.PresentedViewController != null)
{
vc = vc.PresentedViewController;
}
_viewController = vc;
SignIn.SharedInstance.SignInUser();
}
public void Logout()
{
SignIn.SharedInstance.SignOutUser();
}
public void DidSignIn(SignIn signIn, Google.SignIn.GoogleUser user, NSError error)
{
if (user != null && error == null)
_onLoginComplete?.Invoke(new GoogleNativeLogin.Models.GoogleUser()
{
Name = user.Profile.Name,
Email = user.Profile.Email,
Picture = user.Profile.HasImage ? new Uri(user.Profile.GetImageUrl(500).ToString()) : new Uri(string.Empty)
}, string.Empty);
else
_onLoginComplete?.Invoke(null, error.LocalizedDescription);
}
[Export("signIn:didDisconnectWithUser:withError:")]
public void DidDisconnect(SignIn signIn, GoogleUser user, NSError error)
{
// When the user disconnects from app here
}
[Export("signInWillDispatch:error:")]
public void WillDispatch(SignIn signIn, NSError error)
{
//myActivityIndicator.StopAnimating();
}
[Export("signIn:presentViewController:")]
public void PresentViewController(SignIn signIn, UIViewController viewController)
{
_viewController?.PresentViewController(viewController, true, null);
}
[Export("signIn:dismissViewController:")]
public void DismissViewController(SignIn signIn, UIViewController viewController)
{
_viewController?.DismissViewController(true, null);
}
}
安卓
MainActivity.cs 将此代码添加到 MainActivity
...
protected override void OnActivityResult(int requestCode, Result resultCode, Android.Content.Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == 1)
{
GoogleSignInResult result = Auth.GoogleSignInApi.GetSignInResultFromIntent(data);
GoogleManager.Instance.OnAuthCompleted(result);
}
}
...
Google 管理器
public class GoogleManager : Java.Lang.Object, IGoogleManager, GoogleApiClient.IConnectionCallbacks, GoogleApiClient.IOnConnectionFailedListener
{
public Action<GoogleUser, string> _onLoginComplete;
public static GoogleApiClient _googleApiClient { get; set; }
public static GoogleManager Instance { get; private set; }
public GoogleManager()
{
Instance = this;
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DefaultSignIn)
.RequestEmail()
.Build();
_googleApiClient = new
GoogleApiClient.Builder(((MainActivity)Forms.Context).ApplicationContext)
.AddConnectionCallbacks(this)
.AddOnConnectionFailedListener(this)
.AddApi(Auth.GOOGLE_SIGN_IN_API, gso)
.AddScope(new Scope(Scopes.Profile))
.Build();
}
public void Login(Action<GoogleUser, string> onLoginComplete)
{
_onLoginComplete = onLoginComplete;
Intent signInIntent = Auth.GoogleSignInApi.GetSignInIntent(_googleApiClient);
((MainActivity)Forms.Context).StartActivityForResult(signInIntent, 1);
_googleApiClient.Connect();
}
public void Logout()
{
_googleApiClient.Disconnect();
}
public void OnAuthCompleted(GoogleSignInResult result)
{
if (result.IsSuccess)
{
GoogleSignInAccount accountt = result.SignInAccount;
_onLoginComplete?.Invoke(new GoogleUser(){
Name = accountt.DisplayName,
Email = accountt.Email,
Picture = new Uri((accountt.PhotoUrl != null ? $ {accountt.PhotoUrl}" : $"//YOUR_PLACE_HOLDER_IMAGE.jpg//"))}, string.Empty);
} else {
_onLoginComplete?.Invoke(null, "An error occured!");
}
}
public void OnConnected(Bundle connectionHint)
{
}
public void OnConnectionSuspended(int cause)
{
_onLoginComplete?.Invoke(null, "Canceled!");
}
public void OnConnectionFailed(ConnectionResult result)
{
_onLoginComplete?.Invoke(null, result.ErrorMessage);
}
}