مقدمه
احتمالاً تا الان برنامههای زیادی دیدهاید که هنگام ثبت نام و لاگین به برنامه به شما این امکان را میدهند تا با حساب کاربری خود در گوگل در برنامه ثبت نام کنید یا وارد برنامه شوید. در این بخش میخواهم شما را با این تکنیک سودمند آشنا کنم.
پیش نیازها
ورود با گوگل یا Google Sign in پیشنیازهایی دارد که برنامه حتماً باید آنها را داشته باشد تا بتوان از این ابزار در برنامه استفاده کرد.
- یک دستگاه اندروید که از اندروید ۲.۳ یا جدیدتر استفاده میکند و گوگل پلی استور روی آن نصب است. یا یک شبیهساز که Google API را پشتیبانی کند و اندروید آن ۴.۲.۲ یا جدیدتر باشد و گوگل پلی سرویسز نسخه ۹.۸.۰ یا بالاتر روی آن نصب شده باشد.
- آخرین نسخه SDK اندروید
- یک پروژه اندروید که برای اندروید ۲.۳ یا Ginger bread و بالاتر تنظیم شده باشد (minSdkVersion آن ۱۰ یا بیشتر باشد).
- گوگل پلی سرویسز SDK که از درون SDK Manager بخش Extras باید نصب و بروز رسانی کنید.
گرفتن فایل تنظیمات
اگر همه پیش نیازها را دارید، حالا باید برنامه خودتان را در گوگل ثبت کنید و یک فایل تنظیمات بگیرید. برای این کار به اینجا بروید و بر روی دکمه Get a configuration file کلیک کنید:
حالا اسم برنامه و نام بسته برنامه را وارد کنید:
بعد روی دکمه Choose and configure services کلیک کنید و به مرحله بعد بروید:
در این مرحله باید سرویس مورد نظر را انتخاب و مراحل را ادامه دهیم. همانطور که در عکس میبینید ما سرویس Google Sign-In را انتخاب کردهایم. حالا باید SHA-1 کلیدی که برای رمز کردن برنامه استفاده میکنید را به گوگل بدهید. اگر نمیدانید این کلید چیست و چطور باید آن را به دست بیاورید، بخش زیر را بخوانید.
گرفتن کلید 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
اگر به قسمت Certificate fingerprints نگاه کنید میبینید که به سه فرمت متفاوت این اثر انگشت را به ما میدهد و SHA-1 گزینه دوم است. این مقدار را کپی کرده و در قسمت مربوطه در پنل توسعهدهندگان گوگل وارد کنید:
در انتهای این مطلب توضیح کاملی درباره کلید برنامه و آماده کردن برنامه برای انتشار در مارکتها آمده است.
حالا که کد SHA-1 را وارد کردید، Google Sign-In را فعال کرده و سپس فایل تنظیمات را دانلود کنید:
اضافه کردن فایل تنظیمات به پروژه
فایل دانلود شده به نام google-services.json را در شاخه app یا mobile پروژه خود اضافه کنید.
نکته: اگر فقط از سرویس Google Sign-In استفاده میکنید، نیازی نیست فایل را در پروژه کپی کنید ولی اگر از سرویسهای دیگری مثل Cloud Messaging یا Google Analytics استفاده میکنید حتماً فایل را در مسیر گفته شده کپی کنید.
اضافه کردن پلاگین Google Services
پلاگین Google Services برای گریدل اطلاعات فایل تنظیمات را از فایل google-services.json میخواند. برای اضافه کردن این پلاگین به برنامه، باید فایل گریدل مربوط به پروژه را ویرایش کرده و خط زیر را در قسمت dependencies اضافه کنید:
classpath 'com.google.gms:google-services:3.0.0'
و بعد خط زیر را به انتهای گریدل اپ اضافه کنید:
apply plugin: 'com.google.gms.google-services'
و خط زیر را در قسمت dependencies اضافه کنید:
compile 'com.google.android.gms:play-services-auth:10.0.1'
تصویر زیر به شما کمک میکند:
حالا همه کارهایی که پیش نیاز این کار بود را انجام دادیم و وقت آن است که برویم سراغ خود برنامه!
برنامهای که با گوگل لاگین میکند
اول از همه فایل strings.xml را باز کنید و چند تا رشته متنی به آن اضافه کنید:
<string name="btn_logout_from_google">خروج از گوگل</string> <string name="btn_revoke_access">قطع دسترسی به گوگل</string>
حالا یه فایل ساده layout برای برنامه میسازیم:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp" tools:context=".MainActivity" > <LinearLayout android:id="@+id/llProfile" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="20dp" android:orientation="horizontal" android:weightSum="3" android:visibility="gone"> <ImageView android:id="@+id/imgProfilePic" android:layout_width="80dp" android:layout_height="wrap_content" android:layout_weight="1"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:orientation="vertical" android:layout_weight="2" > <TextView android:id="@+id/txtName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dp" android:textSize="20dp" /> <TextView android:id="@+id/txtEmail" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dp" android:textSize="18dp" /> </LinearLayout> </LinearLayout> <com.google.android.gms.common.SignInButton android:id="@+id/btn_sign_in" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="20dp"/> <Button android:id="@+id/btn_sign_out" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/btn_logout_from_google" android:visibility="gone" android:layout_marginBottom="10dp"/> <Button android:id="@+id/btn_revoke_access" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/btn_revoke_access" android:visibility="gone" /> </LinearLayout>
تنها چیزی که احتمالاً برایتان جدید است، ویویی از نوع SignInButton است:
<com.google.android.gms.common.SignInButton android:id="@+id/btn_sign_in" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="20dp"/>
به زودی عملکرد این دکمه را خواهید دید.
کد برنامه
حالا وقت آن است که کار اصلی برنامه را پیادهسازی کنیم. برای شروع MainActivity را باز کنید. کلاس MainActivity رابط یا اینترفیس GoogleApiClient.OnConnectionFailedListener را باید پیادهسازی کند:
public class MainActivity extends AppCompatActivity implements View.OnClickListener, GoogleApiClient.OnConnectionFailedListener { @Override protected void onCreate(Bundle savedInstanceState) { // } @Override public void onStart() { // } @Override public void onClick(View v) { // } @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { // } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { // } private void handleSignInResult(GoogleSignInResult result) { // } private void signIn() { // } private void signOut() { // } private void revokeAccess() { // } private void updateUI(boolean isSignedIn) { // } }
عمداً پیادهسازی متدها رو ننوشتم تا بتوانید یک نگاه کلی به ساختار این کلاس داشته باشید.
مراحل کار بسیار ساده است. اول از همه باید متد onClick را پیادهسازی کنیم. کار اصلی این متد، پیادهسازی عملیات دکمههای Login و Logout و Revoke Access است که در layout این اکتیویتی قبلاً اضافه کرده بودیم:
@Override public void onClick(View v) { int id = v.getId(); switch (id) { case R.id.btn_sign_in: signIn(); break; case R.id.btn_sign_out: signOut(); break; case R.id.btn_revoke_access: revokeAccess(); break; }
به نظرم این متد به قدری واضح است که نیاز به توضیح بیشتر ندارد.
حالا به سراغ متد login میرویم:
private void signIn() { Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); startActivityForResult(signInIntent, RC_SIGN_IN); }
عملکرد این متد هم فوقالعاده ساده است. در این متد ما اکتیویتی مربوط به لاگین گوگل را صدا میزنیم و منتظر جواب آن میمانیم. در این مرحله کاربر به اکتیویتی گوگل هدایت میشود و در آنجا از کاربر پرسیده میشود که آیا میخواهد با حساب کاربری گوگل خود در این برنامه لاگین کند یا نه؟ پاسخ کاربر هر چه که باشد، به متد onActivityResult ارسال میشود. پس حالا نوبت پیادهسازی متد 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); } }
همانطور که میبینید، بعد از بازگشت کاربر از اکتیویتی دوم بررسی میکنیم تا ببینیم آیا کاربر از صفحه لاگین گوگل برگشته است، اطلاعات دریافتی از آن اکتیویتی را به متد handleSignInResult میفرستیم. پس حالا نوبت پیادهسازی این متد است:
private void handleSignInResult(GoogleSignInResult result) { if (result.isSuccess()) { // Signed in successfully, show authenticated UI. GoogleSignInAccount acct = result.getSignInAccount(); String personName = acct.getDisplayName(); String personPhotoUrl = acct.getPhotoUrl().toString(); String email = acct.getEmail(); txtName.setText(personName); txtEmail.setText(email); Glide.with(getApplicationContext()).load(personPhotoUrl) .thumbnail(0.5f) .crossFade() .diskCacheStrategy(DiskCacheStrategy.ALL) .into(imgProfilePic); updateUI(true); } else { // Signed out, show unauthenticated UI. updateUI(false); } }
ببینیم در این متد چه اتفاقی میافتد. ابتدا بررسی میکنیم ببینیم که آیا کاربر با موفقیت به حساب کاربری خود وارد شده و به برنامه ما اجازه داده است تا اطلاعات پایهاش را از گوگل بگیریم یا نه؟ اگر موافقت کرده باشد، با استفاده از کلاس GoogleSignInAccount نام کاربری، آدرس عکس پروفایل و ایمیل وی را میگیریم و صفحه برنامه را با این اطلاعات بروزرسانی میکنیم. در این مطلب درباره گلاید گفتهایم. اگر نخواندهاید یا فراموش کردهاید، یک نگاه دوباره به این مطلب بیاندازید.
اگر به هر دلیلی کاربر با درخواست لاگین با گوگل موافقت نکرده باشد ما باید برنامه را از اطلاعات کاربری پاک کنیم.
فرایند لاگین را با هم دیدیم. حالا میرویم سراغ لاگ اوت. همانطور که حدس میزنید نوبت پیادهسازی متد logout است:
private void signOut() { Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback( new ResultCallback<Status>() { @Override public void onResult(Status status) { updateUI(false); } }); }
پیادهسازی این متد هم بسیار ساده است. در این متد ما با فراخوانی متد signOut از GoogleSignInApi دستور لاگ اوت کاربر را به گوگل ارسال میکنیم. در این جا لازم است یک listener تعریف کنیم تا بعد از اتمام عملیات صدا زده شده و برنامه را به تناسب تغییر دهد.
Revoke یا گرفتن دسترسی هم به سادگی لاگ اوت است.
توضیح: Revoke یعنی گرفتن دسترسی. یعنی برنامه به گوگل اعلام میکند که دیگر دسترسی به اطلاعات کاربر را نمیخواهد. در این حالت اگر کاربر بخواهد دوباره به برنامه وارد شود، باید دوباره به برنامه اجازه دسترسی به اطلاعات خودش را بدهد.
private void revokeAccess() { Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback( new ResultCallback<Status>() { @Override public void onResult(Status status) { updateUI(false); } }); }
حالا ببینیم بعد از اتصال همه این اجزا به هم کلاس MainActivity چه شکلی شده است:
import android.app.ProgressDialog; import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; 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; public class MainActivity extends AppCompatActivity implements View.OnClickListener, GoogleApiClient.OnConnectionFailedListener { private static final String TAG = MainActivity.class.getSimpleName(); private static final int RC_SIGN_IN = 007; private GoogleApiClient mGoogleApiClient; private ProgressDialog mProgressDialog; private SignInButton btnSignIn; private Button btnSignOut, btnRevokeAccess; private LinearLayout llProfileLayout; private ImageView imgProfilePic; private TextView txtName, txtEmail; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnSignIn = (SignInButton) findViewById(R.id.btn_sign_in); btnSignOut = (Button) findViewById(R.id.btn_sign_out); btnRevokeAccess = (Button) findViewById(R.id.btn_revoke_access); llProfileLayout = (LinearLayout) findViewById(R.id.llProfile); imgProfilePic = (ImageView) findViewById(R.id.imgProfilePic); txtName = (TextView) findViewById(R.id.txtName); txtEmail = (TextView) findViewById(R.id.txtEmail); btnSignIn.setOnClickListener(this); btnSignOut.setOnClickListener(this); btnRevokeAccess.setOnClickListener(this); GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestEmail() .build(); mGoogleApiClient = new GoogleApiClient.Builder(this) .enableAutoManage(this, this) .addApi(Auth.GOOGLE_SIGN_IN_API, gso) .build(); // Customizing G+ button btnSignIn.setSize(SignInButton.SIZE_STANDARD); btnSignIn.setScopes(gso.getScopeArray()); } private void signIn() { Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); startActivityForResult(signInIntent, RC_SIGN_IN); } private void signOut() { Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback( new ResultCallback<Status>() { @Override public void onResult(Status status) { updateUI(false); } }); } private void revokeAccess() { Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback( new ResultCallback<Status>() { @Override public void onResult(Status status) { updateUI(false); } }); } private void handleSignInResult(GoogleSignInResult result) { Log.d(TAG, "handleSignInResult:" + result.isSuccess()); if (result.isSuccess()) { // Signed in successfully, show authenticated UI. GoogleSignInAccount acct = result.getSignInAccount(); Log.e(TAG, "display name: " + acct.getDisplayName()); String personName = acct.getDisplayName(); String personPhotoUrl = acct.getPhotoUrl().toString(); String email = acct.getEmail(); Log.e(TAG, "Name: " + personName + ", email: " + email + ", Image: " + personPhotoUrl); txtName.setText(personName); txtEmail.setText(email); Glide.with(getApplicationContext()).load(personPhotoUrl) .thumbnail(0.5f) .crossFade() .diskCacheStrategy(DiskCacheStrategy.ALL) .into(imgProfilePic); updateUI(true); } else { // Signed out, show unauthenticated UI. updateUI(false); } } @Override public void onClick(View v) { int id = v.getId(); switch (id) { case R.id.btn_sign_in: signIn(); break; case R.id.btn_sign_out: signOut(); break; case R.id.btn_revoke_access: revokeAccess(); break; } } @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); } } @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); } }); } } @Override public void onConnectionFailed(@NonNull 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(this); mProgressDialog.setMessage(getString(R.string.loading)); mProgressDialog.setIndeterminate(true); } mProgressDialog.show(); } private void hideProgressDialog() { if (mProgressDialog != null && mProgressDialog.isShowing()) { mProgressDialog.hide(); } } private void updateUI(boolean isSignedIn) { if (isSignedIn) { btnSignIn.setVisibility(View.GONE); btnSignOut.setVisibility(View.VISIBLE); btnRevokeAccess.setVisibility(View.VISIBLE); llProfileLayout.setVisibility(View.VISIBLE); } else { btnSignIn.setVisibility(View.VISIBLE); btnSignOut.setVisibility(View.GONE); btnRevokeAccess.setVisibility(View.GONE); llProfileLayout.setVisibility(View.GONE); } } }
برنامه را تست میکنیم تا ببینیم که آیا به درستی کار میکند یا نه.
تست برنامه
برنامه را اجرا میکنیم. اگر بر روی شبیهساز برنامه را اجرا میکنید،حتماً از یک AVD ساخته شده که Gppgle API دارد استفاده کنید:
بعد از اجرای برنامه، صفحه اول برنامه شبیه تصویر زیر میشود:
بر روی دکمه Sign In کلیک کنید. دو اتفاق ممکن است بیافتد:
اگر حساب کاربری بر روی این دستگاه فعال نشده باشد، از شما میخواهید با حساب کاربری گوگل خود وارد شوید یا یک حساب کاربری بسازید:
اگر حساب کاربری گوگل بر روی دستگاه وجود داشته باشد، از شما میخواهد که اکانت مورد نظر را انتخاب کنید:
بعد از انتخاب حساب کاربری خود، برنامه به حساب کاربری گوگل شما دسترسی خواهد داشت و نام، ایمیل و عکس پروفایل شما را از گوگل خوانده و در صفحه بعد به شما نشان میدهد:
نکته: احتمال میدهم که برنامه نتواند عکس شما را بیاورد، علتش این است که بعضی از سرویسهای گوگل به طرز احمقانهای فیلتر هستند. همانطور که میبینید من هم از فیلترشکن استفاده میکنم.
حالا شما میدانید و اسم و ایمیل و عکس پروفایل کاربر. میتوانید این اطلاعات را به سرور خود ارسال کنید و برای کاربری با این ایمیل یک حساب کاربری ایجاد کنید یا اگر حساب کاربری دارد، او را به برنامه وارد کنید و …. سمت سرور این کار خودش قصه جداگانهای دارد!
آماده کردن برنامه برای انتشار
این برنامه را با کلید دیباگ ساختیم و کلید SHA-1 که ساختیم فقط برای دیباگ برنامه معتبر است. اگر بخواهید برنامه را در مارکت منتشر کنید باید برنامه را با یک کلید اختصاصی امضا کنید و کلید SHA-1 مخصوص آن کلید را در کنسول توسعهدهندگان گوگل وارد کنید. برای این کار ادامه مطلب را بخوانید:
گرفتن کلید SHA-1
همه برنامههای اندروید برای انتشار در گوگل پلی و مارکتهای معتبر باید امضای دیجیتال داشته باشند. گوگل در زمینه امضای دیجیتال سختگیر است و بدون امضای دیجیتال اجازه انتشار برنامهها را نمیدهد. البته در این میان کمی آسانتر گرفته و اجازه میدهد خود ناشر برنامه خودش را امضا کند که اصطلاحاً self-signature نامیده میشود.
برای امضای دیجیتال کردن برنامه، نیاز به یک محل نگهداری کلیدهای امضا دارید. این فایل اصطلاحاً keystore نامیده میشود. در یک keystore میتوانید هر تعداد کلید که میخواهید ذخیره کنید.
زمانی که برنامهای در اکلیپس یا اندروید میسازید، در زمان کامپایل و نصب برنامه، اندروید SDK به صورت خودکار برنامهها را با یک کلید از پیش تعریف شده در keystore پیشفرض امضا میکند.
میتوانید برای گرفتن SHA-1 امضای دیجیتال برنامه از keystore پیشفرض استفاده کنید ولی اکیداً توصیه میکنم یک keystore بسازید و آن را در مکانی امن نگهداری کنید. چون اگر این فایل را از دست بدهید، دیگر نمیتوانید برنامه را با همان امضای قبلی منتشر کنید و اندروید بروزرسانیهای جدید برنامه را به رسمیت نشناخته و کاربر مجبور میشود برای بروزرسانی برنامه ابتدا برنامه قبلی را پاک کند. این مشکل را احتمالاً در بسیاری از برنامههای ایرانی دیدهاید!
برای شروع کار میخواهیم ابتدا یک keystore بسازیم و بعد یک کلید اختصاصی برای برنامه بسازیم. هر دوی این کارها در یک مرحله انجام میشود. ابتدا خط دستور ویندوز (یا ترمینال لینوکس و مک) را باز کرده و به پوشهای که میخواهید keystore در آن ایجاد شود بروید و سپس دستور زیر را اجرا کنید:
keytool -keystore androidkeystore -genkey -alias smartlab
در این دستور androidkeystore نام فایل keystore و smartlab نام کلیدی است که برای این برنامه خواهیم ساخت.
با اجرای این دستور باید مراحل زیر را طی کنید:
- یک رمز برای دسترسی به keystore تعریف کنید.
- رمز تعریف شده را تکرار کنید
- نام و نام خانوادگی خودتان را وارد کنید
- نام واحد سازمانی خودتان را وارد کنید
- نام شرکت یا سازمان خودتان را وارد کنید
- شهر خود را وارد کنید
- استان خود را وارد کنید
- کد دو حرفی اسم کشورتان (در مورد ایران IR) را وارد کنید
- از شما میپرسد که آیا اطلاعات صحیح است؟ yes بزنید
- حالا باید رمز مخصوص کلید smartlab را بزنید و تکرار کنید (اگر میخواهید از همان رمزی که برای keystore تعریف کردید در این کلید هم استفاده شود فقط Enter بزنید).
حالا در شاخه مورد نظر یک فایل androidkeystore ساخته شده است!
حالا باید اثر انگشت یا fingerprint این کلید را بگیریم و در پنل توسعهدهندگان گوگل وارد کنیم. برای این کار دستور زیر را اجرا میکنیم:
keytool -exportcert -list -v -alias smartlab -keystore androidkeystore
اجرای این دستور اثر انگشت کلید smartlab که در فایل نگهدارنده کلید androidkeystore ذخیره شده است را به ما میدهد:
اگر به قسمت Certificate fingerprints نگاه کنید میبینید که به سه فرمت متفاوت این اثر انگشت را به ما میدهد و SHA-1 گزینه دوم است. این مقدار را کپی کرده و در قسمت مربوطه در پنل توسعهدهندگان گوگل وارد کنید.
در ادامه…
برای راحتی کاربر و استفاده بیشتر از برنامه باید بتوانید راههای بیشتر و سادهتری را برای او فراهم کنید. ورود و لاگین با گوگل فقط یکی از این راهها است. فقط برای لاگین کاربر، باید لاگینهای فیسبوک و توئیتر و … را هم برای کاربر فراهم کنید! برنامههای معروف، همه این راه طولانی را برای رضایت کاربران طی میکنند!
فکر میکنم بهتر باشه برای قسمت کدهاتون ویژگی جهت چپ به راست اضافه کنید تا نیازی نباشه به چپ اسکرول کرد.
.syntaxhighlighter {
direction: ltr;
}
دو سال بود میخواستم این کار رو بکنم!
انجام شد!
مزیت این روش نسبت به ثبت نام مستقیم چیه؟
برای مثال کاربر ایمیل خودشو وارد کنه و با اون ثبت نام کنه
راحتی بیشتر کاربر
عدم نیاز به یاد سپردن رمز عبور و فراموشی آن
راحتی خارج شدن از برنامه
برای برنامهها هم بهتره چون هم راحت تر اسم و عکس پروفایل و ایمیل و دوستان و علاقمندیها و … رو به دست میارن
با عرض سلام و خسته نباشید
من فایل androidkeystore را ساختم .
حالا این فایل رو در کدوم پوشه از برنامه باید قرار داده شود؟
چگونه از این امضای دیجیتال استفاده کنم؟
با تشکر از آقای بهزادیان،واقعا مطالبتون عالی و کاربردی هستن …
فایل keystore رو به برنامه اضافه نمیکنید. این فایل رو در جای امن و مطمئنی نگه داری میکنید چون کلیدی که برنامههاتون رو باهاش امضا میکنید نگهداری میکنه. در زمانی که میخواهید برنامه رو برای انتشار آماده کنید، باید طی یه فرایندی برنامه رو با کلیدی که تعریف میکنید و تو این فایل ذخیره میشه امضا کنید. در زمان دیباگ به این کار احتیاجی نیست چون اندروید استودیو برنامه رو با یه کلید به اسم debug امضا میکنه.
بله متوجه شدم …. ولی من قبلا برنامه رو با یه کلید دیگه امضا کردم و منتشرش کردم.حالا اگه با این کلید جدید امضاش کنم … روی نسخه های قبلیش نصب میشه ؟
نه، اگه امضای یه برنامه تغییر کنه اندروید اونو یه برنامه دیگه میدونه و اجازه نصب روی دستگاه رو نمیده و کاربر باید اول نسخه قبلی رو کاملا پاک کنه و بعد نسخه جدید رو نصب کنه
واقعا عالیه مطالبتون ، خیلی ساده و روان توضیح میدید.
در مورد الگوی طراحی در اندروید مانند الگوی MVP ، اگر لطف کنید مطلب و مثالی در موردش به اشتراک بگذارید،خیلی ممنون میشم.
با تشکر
در سه مطلب بعدی (که اولیش همین الان منتشر شد) به موضوع MVP در اندروید میپردازیم.
مطلب بسیار عالی بود. مچکرم.
من میخوام اطلاعاتی که کاربر در اپلیکیشن وارد میکنه و تغییراتی که میده ، روی یه پوشه توی گوگل درایو خودش ذخیره بشه که اگر نرم افزار رو حذف کرد و روی یه دیوایس دیگری نصب کرد نرم افزار رو ، به محض لاگین با حساب گوگل خودش ، تمام دیتایی که ذخیره کرده و تغییراتی که روی نرم افزار داده ، براش قابل دسترس باشه و بیاد روی گوشیش و اگر اپلیکیشن رو مثلاً هم روی گوشی و هم روی تبلتش نصب کرد و با یک حساب روی هر دو دستگاه وارد نرم افزار شد ، این دو با هم سینک بشن و اگر با گوشی تغییراتی دادم ، عیناً همون تغییرات روی دستگاه دیگر (همون تبلت) هم اعمال بشه و به روز رسانی و سینک انجام بشه.
دقیقاً نمیدونم چطوری باید این کار رو انجام داد. یه چیزهایی راجع به Google Drive API خوندم ولی نقشه راه درستی ندارم. ممنونم میشم راهنمایی بفرمایید.
به نظرم برای این کار برید سراغ فایربیس (که گوگل خریده) و از امکانات اون استفاده کنید.
سلام و عرض ادب
آقا من بی نهایت تشکر میکنم ازتون . واقعا عالی بود ۳ روز بود با این کد جنگ میکردم کلافه شده بودم با این مطلب تو عرض ۵ دقیقه . حتی کمتر به نتیجه ای که میخواستم رسیدم . بازم تشکر میکنم . عالی بود . اگه کانال یا گروه تلگرامی دارید برام ارسال کنید بیشتر از مطالبتون استفاده کنم . در پناه خدا .
با سلامو خسته نباشید
میخواستم بپرسم اگه بخوایم از سرور شخصی استفاده کنیم به این صورت که تمام اطلاعات کاربر رو در دیتابیس خودمون سمت سرور ذخیره کنیم چجوری باید عمل کنیم ؟
فرایند احراز هویت کاربران فرایند بسیار پیچیدهایه و کتابها براش نوشته شده. اگر از یک فریمورک در سمت سرور استفاده میکنید (چه جاوا، چه PHP، چه دات نت) همگی مکانیسمهای رایج احراز هویت رو با بالاترین نکات امنیتی پیادهسازی کردن. توصیه من اینه که مستندات فریمورکی که ازش استفاده میکنید رو بخونید
با سلام برای ذخیره ی اطلاعات بازی ها چه روشی را پیشنهاد می کنید تا در هنگام پاک کردن و نصب کردن مجدد برنامه کاربر اطلاعات خود مانند مراحل طی شده میزان سکه ها و… را از دست نده؟
عالی بود ممنون از شما
با سلام
من وقتی دستورات رو در cmd می زنم این پیغام میاد
keytool is not recognized
باید چی کار کنم؟
سلام
من وقتی دستورات مربو به sha-1 در cmd می زنم این پیغام میاد
keytool is not recognized
مشکل کجاس؟
با سلام
این آموزش برای قبل هستش
در حال حاضر گوگل فایلی به اسم google-services.json نمیده
و به این خط هم ارور میده
apply plugin: ‘com.google.gms.google-services’
باید چیکار کرد
سلام مهندس جان
مشکل کار من کجاست که با هربار کلیک روی Signin دوباره کانکت میشم؟
انگار یادش نمیمونه کانکت شده یا چک نمیکنه
میشه راهنمایی کنید؟