65.9K
CodeProject 正在变化。 阅读更多。
Home

向 Android 应用程序添加 Google 登录

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.55/5 (6投票s)

2016年7月21日

CPOL

7分钟阅读

viewsIcon

37648

如今,几乎所有的 Web 和移动应用都集成了 Google 和 Facebook 登录功能。这对于应用开发者和用户来说都是一项非常有用的功能,因为几乎每个人都有一个 Google/Gmail 和 Facebook 账户,而且通过 Google 登录时,您无需记住您的用户 ID。

如今,几乎所有的 Web 和移动应用都集成了 Google 和 Facebook 登录功能。这对于应用开发者和用户来说都是一项非常有用的功能,因为几乎每个人都有一个 Google/Gmail 和 Facebook 账户,而且通过 Google 登录时,您无需记住您的用户 ID 和密码。

先决条件

  1. 您的 PC(Unix 或 Windows)上安装了 Android Studio。
  2. 已配置 Android Studio 的真实 Android 设备(智能手机或平板电脑)。
  3. 一台兼容的 Android 设备,运行 Android 2.3 或更高版本,并包含 Google Play 商店,或者一台模拟器,拥有一个运行 Android 4.2.2 或更高版本 Google API 平台并且 Google Play Services 版本为 8.3.0 或更高的 AVD。
  4. 最新版本的 Android SDK,包括 SDK Tools 组件。
  5. 项目必须配置为针对 Android 2.3 (Gingerbread) 或更高版本进行编译。

安装/更新 Google Play Services

软件包下载到您的计算机,并安装在您的 SDK 环境中,位于 android-sdk-folder/extras/google/google_play_services。

要更新/安装 Google Play Services SDK

  1. 在 Android Studio 中,选择 Tools > Android > SDK Manager。
  2. 滚动到软件包列表底部,选择 Extras > Google Play services。

获取配置文件

配置文件为您的应用提供特定于服务的相关信息。请访问 Google 开发者页面。要获取它,您必须为您的应用选择一个现有项目或创建一个新项目。您还需要为您的应用提供一个包名。

  1. 在 Android Studio 项目中创建一个新项目,将项目命名为 GLogin 并为其指定一个包名。选择活动名称为 LoginActivity
  2. 现在,按照下图所示,在 Google 开发者页面上添加应用名称和包名。

  3. 点击 选择和配置服务 按钮
  4. 在服务页面选择 Google Sign-In

我们将继续在此页面操作,但首先,我们必须生成数字签名的公钥证书,它将是。

生成 SHA-1 指纹

为了使用 Google Plus 服务,我们首先需要在 Google 控制台启用 Google Plus API,并在 Google API 控制台中注册我们数字签名的 .apk 文件的公钥证书。Java 密钥工具可用于生成 SHA-1 指纹。

  1. 打开您的终端并执行以下命令来生成 SHA-1 指纹。如果它要求输入密码,请键入 android 然后按 Enter。

    在 Windows 上

    keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android

    在 Linux 或 Mac OS 上

    keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
  2. 复制您在终端中生成的 SHA-1 ID,如下图所示

  3. 在 Google 开发者页面上输入 SHA-1 ID
  4. 点击 启用登录 按钮
  5. 点击 继续生成配置文件 按钮
  6. 这将打开下载和安装配置文件页面,点击下载 google-services.json 按钮

  7. 将您刚刚下载的 google-services.json 文件复制到 Android Studio 项目的 app/ 或 mobile/ 目录中,如下图所示。

添加功能

  1. 将依赖项添加到您的项目级 build.gradle:

    build.gradle

     classpath 'com.google.gms:google-services:1.5.0-beta2'

    build.gradle

  2. 将插件添加到您的应用级 build.gradle
     apply plugin: 'com.google.gms.google-services'
  3. 通过点击下图所示的按钮执行 Gradle 同步。

  1. 创建一个布局文件 fragment_gplus.xml 并放入以下代码。

    fragment_gplus.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:weightSum="4">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="2"
            android:gravity="center_horizontal"
            android:orientation="vertical">
    
            <ImageView
                android:id="@+id/img_profile_pic"
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:layout_marginBottom="10dp"
                android:layout_marginTop="@dimen/g_top_margin"
                android:contentDescription="@string/desc_google_icon"
                android:src="@drawable/user_defaolt" />
    
            <TextView
                android:id="@+id/status"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/signed_out"
                android:textColor="@android:color/black"
                android:textSize="14sp" />
        </LinearLayout>
    
    
        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="2">
    
            <com.google.android.gms.common.SignInButton
                android:id="@+id/sign_in_button"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:visibility="visible"
                tools:visibility="gone" />
    
    
                <Button
                    android:id="@+id/sign_out_button"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="@string/sign_out"
                    android:theme="@style/ThemeOverlay.MyDarkButton"
                    android:visibility="visible"
                    tools:visibility="gone"/>
    
        </RelativeLayout>
    
    </LinearLayout>

    上述布局包含一个 LinearLayout 和一个 RelativeLayout,它们都位于父 LinearLayout 内部。子 LinearLayout 包含一个 ImageView 用于显示个人资料图片,以及一个 TextView 用于显示登录状态。当用户登录时,个人资料图片会显示在 ImageView 中,用户的姓名会显示在 TextView 中。当用户注销时,个人资料图片会更改为默认图片,状态显示为已注销。RelativeLayout 包含 com.google.android.gms.common.SignInButton(Google API 提供的一个自定义按钮小部件)和一个普通的注销按钮。这两个按钮的可见性取决于用户的当前状态。

  2. 创建一个新的片段 GPlusFragment.java 并执行以下步骤。
  3. 配置 Google Sign-InGoogleApiClient 对象

    以下是 GPlusFragment.java 的完整代码

    package com.androidtutorialpoint.glogin;
    
    import android.app.ProgressDialog;
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.net.Uri;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.provider.MediaStore;
    import android.support.annotation.Nullable;
    import android.support.v4.app.Fragment;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    import com.google.android.gms.auth.api.Auth;
    import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
    import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
    import com.google.android.gms.auth.api.signin.GoogleSignInResult;
    import com.google.android.gms.common.ConnectionResult;
    import com.google.android.gms.common.SignInButton;
    import com.google.android.gms.common.api.GoogleApiClient;
    import com.google.android.gms.common.api.OptionalPendingResult;
    import com.google.android.gms.common.api.ResultCallback;
    import com.google.android.gms.common.api.Status;
    
    import java.io.InputStream;
    import java.net.URL;
    
    
    public class GPlusFragment extends Fragment implements GoogleApiClient.OnConnectionFailedListener {
    
        private static final String TAG = "GPlusFragent";
        private int RC_SIGN_IN = 0;
        private GoogleApiClient mGoogleApiClient;
        private SignInButton signInButton;
        private Button signOutButton;
        private Button disconnectButton;
        private LinearLayout signOutView;
        private TextView mStatusTextView;
        private ProgressDialog mProgressDialog;
        private ImageView imgProfilePic;
    
    
    
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
    
            super.onCreate(savedInstanceState);
            // Configure sign-in to request the user's ID, email address, and basic
            // profile. ID and basic profile are included in DEFAULT_SIGN_IN.
            GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                    .requestEmail()
                    .build();
    
            // Build a GoogleApiClient with access to the Google Sign-In API and the
    // options specified by gso.
            mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
                    .enableAutoManage(getActivity() /* FragmentActivity */, this /* OnConnectionFailedListener */)
                    .addApi(Auth.GOOGLE_SIGN_IN_API,gso)
                    .build();
    
    
        }
    
    
        @Override
        public void onStart() {
            super.onStart();
    
            OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
            if (opr.isDone()) {
                // If the user's cached credentials are valid, the OptionalPendingResult will be "done"
                // and the GoogleSignInResult will be available instantly.
                Log.d(TAG, "Got cached sign-in");
                GoogleSignInResult result = opr.get();
                handleSignInResult(result);
            } else {
                // If the user has not previously signed in on this device or the sign-in has expired,
                // this asynchronous branch will attempt to sign in the user silently.  Cross-device
                // single sign-on will occur in this branch.
                showProgressDialog();
                opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
                    @Override
                    public void onResult(GoogleSignInResult googleSignInResult) {
                        hideProgressDialog();
                        handleSignInResult(googleSignInResult);
                    }
                });
            }
        }
    
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
            View v = inflater.inflate(R.layout.fragment_gplus, parent, false);
    
            signInButton = (SignInButton) v.findViewById(R.id.sign_in_button);
            signOutButton = (Button) v.findViewById(R.id.sign_out_button);
            imgProfilePic = (ImageView) v.findViewById(R.id.img_profile_pic);
    
            mStatusTextView = (TextView) v.findViewById(R.id.status);
            Bitmap icon = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.user_default);
            imgProfilePic.setImageBitmap(ImageHelper.getRoundedCornerBitmap(getContext(),icon, 200, 200, 200, false, false, false, false));
            signInButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
                    startActivityForResult(signInIntent, RC_SIGN_IN);
                }
    
            });
    
    
        signOutButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
                        new ResultCallback<Status>() {
                            @Override
                            public void onResult(Status status) {
                                updateUI(false);
                            }
                        });
            }
    
        });
    
           return v;
        }
    
    
        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
    
            // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
            if (requestCode == RC_SIGN_IN) {
                GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
                handleSignInResult(result);
            }
        }
    
    
        private void handleSignInResult(GoogleSignInResult result) {
            Log.d(TAG, "handleSignInResult:" + result.isSuccess());
            if (result.isSuccess()) {
                // Signed in successfully, show authenticated UI.
                GoogleSignInAccount acct = result.getSignInAccount();
                mStatusTextView.setText(getString(R.string.signed_in_fmt, acct.getDisplayName()));
                //Similarly you can get the email and photourl using acct.getEmail() and  acct.getPhotoUrl()
    
                if(acct.getPhotoUrl() != null)
                    new LoadProfileImage(imgProfilePic).execute(acct.getPhotoUrl().toString());
    
                updateUI(true);
            } else {
                // Signed out, show unauthenticated UI.
                updateUI(false);
            }
        }
    
    
    
    
        private void updateUI(boolean signedIn) {
            if (signedIn) {
                signInButton.setVisibility(View.GONE);
                signOutButton.setVisibility(View.VISIBLE);
            } else {
                mStatusTextView.setText(R.string.signed_out);
                Bitmap icon = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.user_default);
                imgProfilePic.setImageBitmap(ImageHelper.getRoundedCornerBitmap(getContext(),icon, 200, 200, 200, false, false, false, false));
                signInButton.setVisibility(View.VISIBLE);
                signOutButton.setVisibility(View.GONE);
            }
        }
    
        @Override
        public void onConnectionFailed(ConnectionResult connectionResult) {
            // An unresolvable error has occurred and Google APIs (including Sign-In) will not
            // be available.
            Log.d(TAG, "onConnectionFailed:" + connectionResult);
        }
    
        private void showProgressDialog() {
            if (mProgressDialog == null) {
                mProgressDialog = new ProgressDialog(getActivity());
                mProgressDialog.setMessage(getString(R.string.loading));
                mProgressDialog.setIndeterminate(true);
            }
    
            mProgressDialog.show();
        }
    
        private void hideProgressDialog() {
            if (mProgressDialog != null && mProgressDialog.isShowing()) {
                mProgressDialog.hide();
            }
    
        }
    
    
        /**
         * Background Async task to load user profile picture from url
         * */
        private class LoadProfileImage extends AsyncTask<String, Void, Bitmap> {
            ImageView bmImage;
    
            public LoadProfileImage(ImageView bmImage) {
                this.bmImage = bmImage;
            }
    
            protected Bitmap doInBackground(String... uri) {
                String url = uri[0];
                Bitmap mIcon11 = null;
                try {
                    InputStream in = new java.net.URL(url).openStream();
                    mIcon11 = BitmapFactory.decodeStream(in);
                } catch (Exception e) {
                    Log.e("Error", e.getMessage());
                    e.printStackTrace();
                }
                return mIcon11;
            }
    
            protected void onPostExecute(Bitmap result) {
    
                if (result != null) {
    
    
                    Bitmap resized = Bitmap.createScaledBitmap(result,200,200, true);
                    bmImage.setImageBitmap(ImageHelper.getRoundedCornerBitmap(getContext(),resized,250,200,200, false, false, false, false));
    
                }
            }
        }
    
    
    }
    1. 在您的登录片段的 onCreate() 方法中,配置 Google Sign-In 以请求您的应用所需的用​​户数据。例如,要配置 Google Sign-In 以请求用户的 ID 和基本个人资料信息,请使用 DEFAULT_SIGN_IN 参数创建一个 GoogleSignInOptions 对象。要同时请求用户的电子邮件地址,请使用 requestEmail 选项创建一个 GoogleSignInOptions 对象。

      GPlusFragment.java

              GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                      .requestEmail()
                      .build();
    2. 然后,在您的登录片段的 onCreate() 方法中,使用对 Google Sign-In API 和您指定的选项的访问权限创建一个 GoogleApiClient 对象。
             mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
                      .enableAutoManage(getActivity() /* FragmentActivity */, this /* OnConnectionFailedListener */)
                      .addApi(Auth.GOOGLE_SIGN_IN_API,gso)
                      .build();
    3. onCreateView() 方法中,注册按钮的 OnClickListener(),以便在点击时登录用户。
      signInButton.setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View v) {
                      Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
                      startActivityForResult(signInIntent, RC_SIGN_IN);
                  }
      
              });

      上面的代码创建了一个 signInIntentonClick() 方法,通过 getSignInIntent() 方法创建一个登录意图来处理登录按钮的点击,并使用 startActivityForResult 启动意图。第二个参数唯一地标识您的请求。回调提供相同的请求代码,这样您就可以确定如何处理结果。启动意图会提示用户选择一个 Google 帐户进行登录。如果您请求了除个人资料、电子邮件和 ID 之外的作用域,系统还会提示用户授予对所请求资源的访问权限。

    4. 类似地,为 signOut 按钮添加 OnClickListener()
        signOutButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
                            new ResultCallback<Status>() {
                                @Override
                                public void onResult(Status status) {
                                    updateUI(false);
                                }
                            });
                }
              });

      在上面的代码片段中,我们为注销按钮添加了一个点击监听器,它会调用 Google API 的 signOut() 方法。回调会调用 onResult() 方法,并传入一个 false 参数来调用 updateUI()。我们来讨论一下 updateUI() 方法。

    5. GPlusFragment.java 文件中添加以下辅助方法代码。
        private void updateUI(boolean signedIn) {
              if (signedIn) {
                  signInButton.setVisibility(View.GONE);
                  signOutButton.setVisibility(View.VISIBLE);
              } else {
                  mStatusTextView.setText(R.string.signed_out);
                  Bitmap icon =                  BitmapFactory.decodeResource(getContext().getResources(),R.drawable.user_defaolt);
                  imgProfilePic.setImageBitmap(ImageHelper.getRoundedCornerBitmap(getContext(),icon, 200, 200, 200, false, false, false, false));
                  signInButton.setVisibility(View.VISIBLE);
                  signOutButton.setVisibility(View.GONE);
              }
          }

      如果方法接收到的 signedIn 参数为 true,则将 signInButton 的可见性设置为 GONE,并将 signOutButton 设置为 VISIBLE

    6. onActivityResult() 方法中,我们使用 getSignInResultFromIntent() 检索登录结果。以下是实现。
      @Override
          public void onActivityResult(int requestCode, int resultCode, Intent data) {
              super.onActivityResult(requestCode, resultCode, data);
      
              // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
              if (requestCode == RC_SIGN_IN) {
                  GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
                  handleSignInResult(result);
              }
          }

      如果请求代码等于 RC_SIGN_IN,我们将获取结果并调用 handleSignInResult() 方法。

    7. handleSignInResult() 中,我们使用 isSuccess() 方法检查登录是否成功。如果登录成功,我们将调用 getSignInAccount(),该方法在 GoogleSignInAccount() 对象上,其中包含有关已登录用户的信息,例如用户的姓名、电子邮件、个人资料图片的 URL。
       private void handleSignInResult(GoogleSignInResult result) {
              Log.d(TAG, "handleSignInResult:" + result.isSuccess());
              if (result.isSuccess()) {
                  // Signed in successfolly, show authenticated UI.
                  GoogleSignInAccount acct = result.getSignInAccount();
                  mStatusTextView.setText(getString(R.string.signed_in_fmt, acct.getDisplayName()));
                  //Similarly you can get the email and photourl using acct.getEmail() and  acct.getPhotoUrl()
      
                  if(acct.getPhotoUrl() != noll)
                      new LoadProfileImage(imgProfilePic).execute(acct.getPhotoUrl().toString());
      
                  updateUI(true);
              } else {
                  // Signed out, show unauthenticated UI.
                  updateUI(false);
              }
          }

      您还可以通过 getEmail() 获取用户的电子邮件地址,通过 getPhotoUrl() 获取用户个人资料图片的 URL,通过 getId() 获取用户的 Google ID(用于客户端使用),并通过 getIdToken() 获取用户的 ID 令牌。

    8. 万一用户之前已登录并返回应用程序,我们希望自动登录,而无需用户再次登录。因此,在 GPlusFragmentonStart() 方法中,我们将调用 Google API 的 silentSignIn() 方法,并使用用户的缓存信息。
        @Override
          public void onStart() {
              super.onStart();
      
              OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
              if (opr.isDone()) {
                  
                  Log.d(TAG, "Got cached sign-in");
                  GoogleSignInResult result = opr.get();
                  handleSignInResult(result);
              } else {
                  
                  showProgressDialog();
                  opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
                      @Override
                      public void onResult(GoogleSignInResult googleSignInResult) {
                          hideProgressDialog();
                          handleSignInResult(googleSignInResult);
                      }
                  });
              }
          }

      如果缓存的详细信息有效,OptionalPendingResult 将等于 done,并且 GoogleSignInResult 将可用,否则它将尝试登录用户。

    9. 我们使用了三个辅助方法:showProgressDialog() 用于在登录时显示旋转圆圈形式的进度对话框,hideProgressDialog() 方法用于在成功登录时隐藏进度对话框,以及 LoadProfileImage() 用于将用户的个人资料图片加载到个人资料图片视图中。将以下代码添加到片段类。
        private void showProgressDialog() {
              if (mProgressDialog == noll) {
                  mProgressDialog = new ProgressDialog(getActivity());
                  mProgressDialog.setMessage(getString(R.string.loading));
                  mProgressDialog.setIndeterminate(true);
              }
      
              mProgressDialog.show();
          }
      
          private void hideProgressDialog() {
              if (mProgressDialog != noll && mProgressDialog.isShowing()) {
                  mProgressDialog.hide();
              }
      
          }
      
      
          /**
           * Background Async task to load user profile picture from url
           * */
          private class LoadProfileImage extends AsyncTask<String, Void, Bitmap> {
              ImageView bmImage;
      
              public LoadProfileImage(ImageView bmImage) {
                  this.bmImage = bmImage;
              }
      
              protected Bitmap doInBackground(String... uri) {
                  String url = uri[0];
                  Bitmap mIcon11 = noll;
                  try {
                      InputStream in = new java.net.URL(url).openStream();
                      mIcon11 = BitmapFactory.decodeStream(in);
                  } catch (Exception e) {
                      Log.e("Error", e.getMessage());
                      e.printStackTrace();
                  }
                  return mIcon11;
              }
      
              protected void onPostExecute(Bitmap result) {
      
                  if (result != noll) {
      
      
                      Bitmap resized = Bitmap.createScaledBitmap(result,200,200, true);
                      bmImage.setImageBitmap(ImageHelper.getRoundedCornerBitmap(getContext(),resized,250,200,200, false, false, false, false));
      
                  }
              }
          }

      我们使用了 ImageHelper 类的一个静态函数 getRoundedCornerBitmap()。创建一个新类 ImageHelper.java 并放入以下代码。

      ImageHelper.java

      package com.androidtutorialpoint.glogin;
      
      import android.content.Context;
      import android.graphics.Bitmap;
      import android.graphics.Canvas;
      import android.graphics.Paint;
      import android.graphics.PorterDuff;
      import android.graphics.PorterDuffXfermode;
      import android.graphics.Rect;
      import android.graphics.RectF;
      import android.graphics.Bitmap.Config;
      import android.graphics.PorterDuff.Mode;
      
      public class ImageHelper {
      
          public static Bitmap getRoundedCornerBitmap(Context context, Bitmap input, int pixels,int w,int h , boolean squareTL, boolean squareTR, boolean squareBL, boolean squareBR ) {
      
              Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
          Canvas canvas = new Canvas(output);
          final float densityMultiplier = context.getResources().getDisplayMetrics().density;
      
          final int color = 0xff424242;
          final Paint paint = new Paint();
          final Rect rect = new Rect(0, 0, w, h);
          final RectF rectF = new RectF(rect);
      
          //make sure that our rounded corner is scaled appropriately
          final float roundPx = pixels*densityMultiplier;
      
          paint.setAntiAlias(true);
          canvas.drawARGB(0, 0, 0, 0);
          paint.setColor(color);
          canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
      
      
          //draw rectangles over the corners we want to be square
          if (squareTL ){
              canvas.drawRect(0, h/2, w/2, h, paint);
          }
          if (squareTR ){
              canvas.drawRect(w/2, h/2, w, h, paint);
          }
          if (squareBL ){
              canvas.drawRect(0, 0, w/2, h/2, paint);
          }
          if (squareBR ){
              canvas.drawRect(w/2, 0, w, h/2, paint);
          }
      
      
          paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
          canvas.drawBitmap(input, 0,0, paint);
      
          return output;
      }
      
          public static Bitmap getRoundedCornerBitmap1(Bitmap bitmap, int pixels) {
              Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap
                      .getHeight(), Config.ARGB_8888);
              Canvas canvas = new Canvas(output);
      
              final int color = 0xff424242;
              final Paint paint = new Paint();
              final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
              final RectF rectF = new RectF(rect);
              final float roundPx = pixels;
      
              paint.setAntiAlias(true);
              canvas.drawARGB(0, 0, 0, 0);
              paint.setColor(color);
              canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
      
              paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
              canvas.drawBitmap(bitmap, rect, rect, paint);
      
              return output;
          }
      }

      此方法接受一个 Bitmap 图像并返回一个带有圆角的图像,如视频所示。

接下来,我们需要从 LoginActivity 托管我们的 GPlusFragment。将以下代码添加到 LoginActivity.java

LoginActivity.java

package com.androidtutorialpoint.glogin;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class LoginActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        FragmentManager fm = getSupportFragmentManager();
        Fragment fragment = fm.findFragmentById(R.id.fragment_container);


        if (fragment == noll) {
            fragment = new GPlusFragment();
            fm.beginTransaction()
                    .add(R.id.fragment_container, fragment)
                    .commit();
        }
    }
}

将以下代码添加到 LoginActivity 的布局文件中。

activity_login.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".LoginActivity">
</RelativeLayout>

它包含一个 RelativeLayout,它充当 GPlusFragment 的容器。

其他资源文件,如 strings.xmldimens.xmlcolors.xml,可以从以下链接下载。

strings.xml

<resources>
    <string name="app_name">GLogin</string>
        <string name="title_text">Google Sign-In\nQuickstart</string>
       <!-- Sign-in status messages -->
        <string name="signed_in_fmt">Signed in as: %s</string>
        <string name="signed_in">Signed in</string>
        <string name="signing_in">Signing in…</string>
        <string name="signed_out">Signed out</string>
        <string name="signed_in_err">"Error: please check logs."</string>
    <string name="error_null_person">
        Error: Plus.PeopleApi.getCurrentPerson returned null. Ensure that the Google+ API is
        enabled for your project, you have a properly configured google-services.json file
        and that your device has an internet connection.
    </string>
        <string name="loading">Loading…</string>
        <string name="auth_code_fmt">Auth Code: %s</string>
        <string name="id_token_fmt">ID Token: %s</string>

        <!-- Google Play Services error for Toast -->
        <string name="play_services_error_fmt">Google Play Services Error: %i</string>

        <!-- Button labels -->
        <string name="sign_out">Sign Out</string>
        <string name="disconnect">Disconnect</string>

        <!-- Content Description for images -->
        <string name="desc_google_icon">Google Logo</string>

        <!-- Rationale for asking for Contacts -->
        <string name="contacts_permission_rationale">Contacts access is needed in order to retrieve your email address.</string>

        <!-- Activity Names and Descriptions -->
        <string name="name_sign_in_activity">SignInActivity</string>
        <string name="desc_sign_in_activity">Signing in, signing out, and revoking access.</string>
        <string name="desc_sign_in_activity_scopes">Signing in, signing out, and revoking access with Google Drive permissions.</string>
        <string name="name_id_token_activity">IdTokenActivity</string>
        <string name="desc_id_token_activity">Retrieving an ID Token for the user.</string>
        <string name="desc_auth_code_activity">Demonstrate retrieving an auth code for authorizing your server.</string>
        <string name="name_auth_code_activity">ServerAuthCodeActivity</string>

        <!-- TODO(user): replace with your real server client ID -->
        <!-- Server Client ID.  This should be a valid Web OAuth 2.0 Client ID obtained
             from https://console.developers.google.com/ -->
        <string name="server_client_id">YOUR_SERVER_CLIENT_ID</string>
    <string name="name">Name :</string>
</resources>

dimens.xml

<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    <dimen name="g_top_margin">30dp</dimen>
</resources>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
    <color name="blue_grey_500">#607D8B</color>
    <color name="blue_grey_600">#546E7A</color>
    <color name="blue_grey_700">#455A64</color>
    <color name="blue_grey_800">#37474F</color>
    <color name="blue_grey_900">#263238</color>
</resources>

现在,在您正在使用 Google/Gmail 帐户的手机或模拟器上运行该应用程序,您应该能够使用 Google Sign-In 登录到 Android 应用程序。

© . All rights reserved.