چنانچه یک اپلیکیشن اندرویدی نیاز به نگهداری اطلاعاتی از شما داشته باشد به یک شناسه یکتا نیاز دارد که اکثرا از ایمیل یا در برخی برنامهها مثل پیامرسانها از شماره تلفن شخص استفاده میکنند. ثبت نام با ایمیل یک سری دردسرهای خودش را دارد. مانند پرکردن چندین کادر مختلف بخصوص وارد نمودن رمزعبور و همچنین اطمینان از صحت ایمیل وارد شده با ارسال لینک فعالسازی و حتی به یاد داشتن این مشخصات در زمان ورود مجدد باعث شده که گوگل روشی سادهتر را ارائه بدهد (البته امکان ورود با حسابهای کاربری دیگر همچون فیسبوک نیز وجود دارد.).
از آنجایی که کاربران سیستم عامل اندروید از اکانت گوگل خود در بخش اکانت دستگاه استفاده میکنند، این روش نیز با استفاده از این حسابکاربری هویت شخص را به برنامه اندروید معرفی میکند. در ادامه روش پیادهسازی این روش توضیح داده خواهد شد. پروژه این مطلب در github قرار داده شده که میتوانید از آن استفاده کنید.
نیازمندیهای برنامه:
- این برنامه به اندورید ۲.۳ به بالا نیاز دارد.
- در صورت استفاده از شبیهساز به نسخه ۴.۲.۲ اندروید نیازمند است.
- باید حداقل نسخه ۸.۴.۰ کتابخانه Google Play Service در دسترس باشد.
قبل از شروع به کار از بخش SDK manager پکیج Google Play Services را دانلود کنید.
برای دسترسی به این امکان گوگل نیاز به فایل تنظیمات وجود دارد. این فایل از آدرس و طی مراحل بعدی دریافت میشود. دقت کنید که به دلیل تحریم فنآوری اجازه دسترسی به این سایت از آیپی ایران وجود ندارد. با مراجعه به آدرس با صفحه زیر روبهرو میشوید. در این بخش نام برنامه و اسم پکیج را وارد کنید:
سپس بر روی دکمه Choose and configure services کلیک کنید.
در این بخش سرویس Google Sign-In رو انتخاب کنید و صفحه را به سمت پایین اسکرول کنید
در این بخش برای شناسایی کلاینت مورد نظر یعنی سیستم شما نیاز به کد SHA-1 امضا دیجیتال شما دارد. برای دسترسی به این کد ابتدا وارد ترمینال شده و دستور زیر را وارد کنید:
keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android
با اجرای دستور فوق در ویندوز و یا دستور پایین در لینوکس:
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
صفحه مشابه تصویر زیر نمایش داده میشه:
در این تصویر SHA-1 نمایش داده شده است. مقدار آن را کپی کرده و در داخل کادر تصویر قبل وارد کنید، سپس بر روی Enable Google Sign-In کلیک کنید. صفحه زیر نمایش داده میشود:
با کلیک بر روی گزینه Generate Configuration files به صفحه زیر منتقل شده و با کلیک بر روی Download google-services.json فایل تنظیمات ورود با حسابکاربری دانلود میشود. دقت کنید که باید کمی به سمت بالای صفحه اسکرول کنید.
فایل دانلود شده را بدون هیچ گونه تغییر به پوشه app پروژه منتقل کنید. بخش دریافت فایل تنظیمات از گوگل به اتمام رسید. در ادامه به آموزش کدنویسی آن میپردازیم.
پروژهای جدید در اندروید استودیو ایجاد کنید. در بخش gradle مربوط به app مقادیر زیر را در بخش dependencies وارد کنید:
// Dependency for Google Sign-In compile 'com.google.android.gms:play-services-auth:8.4.0' // Dependency need for loading image of profile compile 'com.squareup.picasso:picasso:2.5.2'
کتابخانه اول برای دسترسی به api تایید هویت گوگل سرویس و دومی برای بارگذاری عکس پروفایل حسابکاربری جیمیل مورد استفاده قرار میگیرد. برای parse کردن مقادیر داخل فایل کانفیگ دانلود شده، به پلاگین گوگل سرویس نیاز است. این خط را به آخر همین فایل gradle اضافه کنید:
apply plugin: 'com.google.gms.google-services'
به dependencies فایل gradle در بخش پروژه، خط زیر رو اضافه کنید:
classpath 'com.google.gms:google-services:2.0.0-alpha6'
سپس منتظر بمانید تا کار sync کردن کتابخانهها به اتمام برسد. حتما برای دسترسی به resourceهای پلاگین اضافه شده، پروژه رو یک بار rebuild کنید.
طراحی بخش UI ساده است. کد اون رو در زیر مشاهده میکنید:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="ir.bkhezry.googlelogin.MainActivity"> <RelativeLayout android:id="@+id/llProfile" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="20dp" android:orientation="horizontal" android:padding="40dp" android:visibility="gone"> <ImageView android:id="@+id/imgProfilePic" android:layout_width="80dp" android:layout_height="80dp" /> <TextView android:id="@+id/txtName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@+id/imgProfilePic" android:padding="5dp" android:textSize="20dp" /> <TextView android:id="@+id/txtEmail" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/txtName" android:layout_toRightOf="@+id/imgProfilePic" android:padding="5dp" android:textSize="18dp" /> <Button android:id="@+id/btn_sign_out" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/imgProfilePic" android:layout_marginBottom="10dp" android:text="Sign Out" android:visibility="visible" /> <Button android:id="@+id/btn_revoke_access" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/btn_sign_out" android:text="Revoke Access" android:visibility="visible" /> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <com.google.android.gms.common.SignInButton android:id="@+id/sign_in_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:padding="40dp" /> </RelativeLayout> </android.support.constraint.ConstraintLayout>
رابط کاربری شامل بخش نمایش اطلاعات حسابکاربری، دکمههای خروج و revoke کردن دسترسی به حسابکاربری و دکمه ورود با حسابکاربری است. برای این دکمه از المان موجود در پلاگین گوگل سرویس استفاده شده است:
در کلاس MainActivity پیادهسازی برنامه بدین صورت است:
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestEmail() .build();
ابتدا نمونهای از تنظیمات ورود ایجاد میشود در اینجا تنظیمات پیشفرض برای دریافت اطلاعات پایهای حسابکاربری همچون ایمیل، نامکاربری و آدرس عکس پروفایل کاربر درخواست میشود.
در ادامه کلاینتی برای دسترسی به حسابکاربری با تنظیماتی که در کد قبل انجام شده است، ایجاد میگردد:
mGoogleApiClient = new GoogleApiClient.Builder(this) .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */) .addApi(Auth.GOOGLE_SIGN_IN_API, gso) .build();
در کد مربوط به رویداد کلیک دکمه ورود به حسابکاربری کد زیر قرار میگیرد:
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); startActivityForResult(signInIntent, RC_SIGN_IN);
با اجرای این کد یک Intent که مربوط به نمایش بخش انتخاب حسابهای کاربری است، فراخوانی خواهد شد:
پس از برگشت از این Intent تابع onActivityResult اجرا خواهد شد که کد آن بدین صورت است:
@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); } }
مقدار بازگشتی از Intent به تابع handleSignInResult ارسال میگردد. در این تابع نتیجه ورود به حسابکاربری بررسی میشود در صورت موفقیتآمیز بودن، اطلاعات برگشتی که شامل نام کاربری، ایمیل و آدرس عکس پروفایل است دریافت شده و برای نمایش به UI ارسال میشوند:
private void handleSignInResult(GoogleSignInResult result) { Log.d(TAG, "handleSignInResult:" + result.isSuccess()); if (result.isSuccess()) { // Signed in successfully, show authenticated UI. GoogleSignInAccount acct = result.getSignInAccount(); String personName = acct.getDisplayName(); Uri personPhotoUrl = acct.getPhotoUrl(); String email = acct.getEmail(); txtName.setText(personName); txtEmail.setText(email); Picasso.with(MainActivity.this).load(personPhotoUrl).into(imgProfilePic); updateUI(true); } else { // Signed out, show unauthenticated UI. updateUI(false); } }
برای نمایش عکس از کتابخانه Picasso استفاده شده است که تنها با یک خط، عکس پروفایل را نمایش میدهد. سپس تابع updateUI با مقدار صحیح اجرا میشود:
private void updateUI(boolean isSignedIn) { if (isSignedIn) { signInButton.setVisibility(View.GONE); llProfileLayout.setVisibility(View.VISIBLE); } else { signInButton.setVisibility(View.VISIBLE); llProfileLayout.setVisibility(View.GONE); } }
با وارد شدن به حساب کاربری دکمه ورود به حساب حذف شده و بخش نمایش اطلاعات کاربری نمایش داده میشود. در زمان خروج از حساب یا revoke کردن حسابکاربری عکس این عمل روی میدهد.
تابعهای خروج و revoke کردن حسابکاربری به صورت زیر پیادهسازی شدهاند:
private void signOut() { Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback( new ResultCallback<Status>() { @Override public void onResult(Status status) { // [START_EXCLUDE] updateUI(false); // [END_EXCLUDE] } }); } private void revokeAccess() { Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback( new ResultCallback<Status>() { @Override public void onResult(Status status) { // [START_EXCLUDE] updateUI(false); // [END_EXCLUDE] } }); }
با استفاده از Api گوگل عمل خروج و یا revoke انجام میشود، پس از انجام اینکار، UI بهروز شده و دکمه ورود مجددا نمایش داده میشود.
تنها بخش باقیمانده کد، مربوط به زمانی است که به حسابکاربری وارد شدهاید و برنامه را بسته و دوباره باز میکنید. با این کار تابع OnStart فراخوانی خواهد. ورود به حسابکاربری در بخش گوگل پلی سرویس دستگاه شما، کش خواهد شد با استفاده از کد زیر این بخش بررسی خواهد شد. در صورتی که قبلا وارد شده باشید، اطلاعات بازیابی شده و نمایش داده میشوند.
@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); } }); } }
در نسخه ۹ گوگل پلی سرویس و استفاده از کتابخانه ۸.۴.۰ در کدنویسی پس از نمایش Intent مربوط به انتخاب حسابکاربری و انتخاب آن، بخش اجازه دسترسی به حسابکاربری نمایش داده نشد. این بخش گویا در نسخه اخیر تغییر یافته و برای دسترسی به اطلاعات پایه حسابکاربری نیاز به اجازه وجود ندارد. برای اطلاعات بیشتر به این آدرس مراجعه کنید.
مثل همیشه عالی
ممنون
واقعا عالی و ثمر بخش بود این راهکار . مرسی
بسیار مفید و کاربردی مانند دیگر پست های شما . سپاس
سلام خسته نباشید ممنون از آموزش خوبتون…
فقط من یه مشکل داشتم ممنون می شم راهنمایی بفرمائید:
تمامی مراحل رو انجام دادم دکمه sign in هم میاد ولی بعد از انتخاب حساب کاربری، نام و پروفایل و غیره نشون داده نمی شه علت چیه؟ ممنون
سلام،
لطفا پروژه نمونهای که داخل گیتهاب قرار دادم رو تست کنید.
اگر مشکل داشت اون هم، بهم اطلاع بدید.
سلام خسته نباشید من پروژه ای تو گیت هاب گذاشتین رو دانلود کردم و تو اندروید استودیو ازش فایل apk گرفتم ولی باز همون مشکل رو داره
من اپلیکیشن رو تست کردم و مشکلی نداشت.
لطفا logcat رو به دنبال خطای احتمالی، بررسی کنید.
میشه یه وقت کوچیکی بذارید و با تیم ویور وصل بشین به کامپیوتر من و نگاه کنید… لطفا
این ارور رو میده اول شروع پروژه
Error:Failed to find Build Tools revision 23.0.3
Install Build Tools 23.0.3 and sync project
حاجی خیلی ردیفه افرین
ممنون عزیزم خیلی کاربری بود برای من. فقط ی نکته که به مشکل خوردم گرفتن SH1 بود که از طریق لینک زیر اوکی ش کردم.
https://stackoverflow.com/a/33479550/8040697
سلام ممنون بابت آموزش خوبتون. من کاملا پیاده سازی کردم اینو ولی وقتی میخوام sign in کنم اروری که به خاطر تحریم هست رو نشونم میده تو لاگ کت Your client does not have permission to get URL from this server. That’s all we know. ولی وقتی وی پی ان رو ورشن میکنم کدم کاملا درست کار میکنه و وارد میشه. مشکل چی هست یعنی جدیدا نمیشه استفاده کرد؟ یا کد من اشتباهه