تالار گفتمان nCIS.ir

نسخه‌ی کامل: آموزش فعالسازی نرم‌افزار با کمک پیامک
شما در حال مشاهده نسخه آرشیو هستید. برای مشاهده نسخه کامل کلیک کنید.
شاید خیلی‌ها براشون سؤال باشه که برنامه‌هایی مثل Telegram و... چطوری ازطریق پیامک فعال میشن و کدی که دریافت میشه توی برنامه وارد میشه و اعتبارسنجی و... اتفاق میفته. خوب توی این تاپیک میخوام خیلی خلاصه و جمع‌وجور و بصورت مرحله به مرحله این کار رو آموزش بدم. توی این روش، پیامک با کلیک روی دکمه «ارسال کد» ازطریق سایت ارسال میشه به گوشی فرد و بعد از ورود توی کادر مربوطه و کلیک روی دکمه «فعالسازی»، حساب کاربر فعال میشه.

با ما همراه باشید.
مرحله اول، تغییرات عمومی

اول از همه باید توی AndroidManifest.xml این مجوزها رو به برنامه بدین:
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />

دقت کنید که چون پیامک توی این روشی که میخوام توضیح بدم ازطریق سایت ارسال میشه، پس مجوز android.permission.SEND_SMS رو نیاز نداریم.

حالا اکتیویتی Login رو به این شکل بعنوان اکتیویتی اصلی معرفی کنید (در ادامه اون رو میسازیم) :
<activity
    android:name=".LoginActivity"
    android:label="@string/title_activity_login"
    android:theme="@style/AppTheme.NoActionBar"
    android:windowSoftInputMode="adjustNothing">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

دقت کنید که اکتیویتی دیگه‌ای intent-filter های اکشن MAIN و دسته‌بندی LAUNCHER رو نداشته باشه. با این کار، وقتی برنامه اجرا میشه، اکتیویتی لاگین شروع به کار میکنه.

در قدم بعدی باید یک کلاس Application اختصاصی بسازیم:
public class App extends Application {
    public static Context context;
    public static AppCompatActivity currentActivity;

    @Overrice
    public void onCreate() {
        super.onCreate();
        context = getApplicationContext();
    }
}

و بعد باید این کلاس رو توی مانیفست معرفی کنیم:
<application
    android:name=".App"
    ... />

حالا باید یک کلاس از AppCompatActivity مشتق کنید و این کد رو داخلش بنویسید:
public class ActivityEnhanced extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
        App.currentActivity = this;
    }

    @Override
    protected void onResume() {
        super.onResume();
        App.currentActivity = this;
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        App.currentActivity = this;
    }
}

و درنهایت اکتیویتی‌های خودتون رو بجای اینکه مستقیماً از AppCompatActivity مشتق بشن، از کلاس ActivityEnhanced خودتون مشتق کنید.
مرحله دوم، تعریف یک Listener برای دریافت پیامک

خوب ما الان باید یه شنونده برای رویدادی طراحی کنیم که در زمان دریافت پیامک، تولید میشه. اسمش رو OnSmsReceivedListener میگذاریم. یه Interface جدید به این شکل تعریف کنید:
public interface OnSmsReceivedListener {
    void onSmsReceiver(String message, String phone, EditText editText);
}
مرحله سوم، طراحی رابط گرافیکی اکتیویتی لاگین

خوب این اکتیویتی رو میشد با کمک خود Android Studio هم بسازیم و دیگه لازم نبود دستی به مانیفست اضافه کنیم ولی من عمداً توضیح دادم که بدونید چه تغییری باید توی مانیفست برای معرفی این اکتیویتی بعنوان نقطه شروع به کار برنامه، انجام بدین. اول از همه این کد رو به فایل res/values/styles.xml اضافه کنید (داخل تگ resources) :
<style name="AppTheme.NoActionBar">
  <item name="windowActionBar">false</item>
  <item name="windowNoTitle">true</item>
</style>

این همون استایلی هست که توی مانیفست برای اکتیویتی لاگین انتخاب کردیم. با این کار، نوار Action و عنوان دیگه ظاهر نمیشه و برنامه توی اکتیویتی لاگین بصورت یه صفحه سفید بدون منوهای بالا و... ظاهر میشه. حالا باید فایل لی‌اوت این اکتیویتی رو بسازیم. برای این کار، من این قالب رو ایجاد کردم:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  app:layout_behavior="@string/appbar_scrolling_view_behavior"
  tools:context="ir.ncis.jobbank.LoginActivity">

  <LinearLayout
      android:id="@+id/lytSend"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginBottom="@dimen/activity_vertical_margin"
      android:layout_marginLeft="@dimen/activity_horizontal_margin"
      android:layout_marginRight="@dimen/activity_horizontal_margin"
      android:layout_marginTop="@dimen/activity_vertical_margin"
      android:orientation="vertical">

      <LinearLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_gravity="center_horizontal"
          android:orientation="horizontal">

          <EditText
              android:id="@+id/edtName"
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:layout_weight="1"
              android:hint="@string/name"
              android:singleLine="true" />

          <TextView
              android:id="@+id/txtName"
              android:layout_width="64dp"
              android:layout_height="wrap_content"
              android:text="@string/name"
              android:textColor="#000000"
              android:textSize="16sp" />
      </LinearLayout>

      <LinearLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_gravity="center_horizontal"
          android:orientation="horizontal">

          <EditText
              android:id="@+id/edtMobile"
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:layout_weight="1"
              android:hint="@string/sample_mobile"
              android:inputType="phone"
              android:singleLine="true" />

          <TextView
              android:id="@+id/txtMobile"
              android:layout_width="64dp"
              android:layout_height="wrap_content"
              android:text="@string/mobile"
              android:textColor="#000000"
              android:textSize="16sp" />
      </LinearLayout>

      <Button
          android:id="@+id/btnSend"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_gravity="center_horizontal"
          android:background="@color/colorPrimary"
          android:padding="8dp"
          android:text="@string/send_activation_code"
          android:textColor="#ffffff"
          android:textSize="16sp" />

      <Button
          android:id="@+id/btnHaveCode"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_gravity="center_horizontal"
          android:layout_marginBottom="8dp"
          android:layout_marginTop="8dp"
          android:background="@color/colorPrimary"
          android:padding="8dp"
          android:text="@string/i_have_code"
          android:textColor="#ffffff"
          android:textSize="16sp" />
  </LinearLayout>

  <LinearLayout
      android:id="@+id/lytActivate"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginBottom="@dimen/activity_vertical_margin"
      android:layout_marginLeft="@dimen/activity_horizontal_margin"
      android:layout_marginRight="@dimen/activity_horizontal_margin"
      android:layout_marginTop="@dimen/activity_vertical_margin"
      android:orientation="vertical">

      <LinearLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_gravity="center_horizontal"
          android:orientation="horizontal">

          <EditText
              android:id="@+id/edtCode"
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:layout_weight="1"
              android:hint="@string/code"
              android:inputType="number"
              android:singleLine="true" />

          <TextView
              android:id="@+id/txtCode"
              android:layout_width="64dp"
              android:layout_height="wrap_content"
              android:text="@string/code"
              android:textColor="#000000"
              android:textSize="16sp" />
      </LinearLayout>

      <TextView
          android:id="@+id/txtWaiting"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="@string/wait_code"
          android:textAlignment="center"
          android:textColor="#777777"
          android:textSize="16sp" />

      <Button
          android:id="@+id/btnActivate"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_gravity="center_horizontal"
          android:layout_marginBottom="8dp"
          android:layout_marginTop="8dp"
          android:background="@color/colorPrimary"
          android:padding="8dp"
          android:text="@string/activate"
          android:textColor="#ffffff"
          android:textSize="16sp" />

      <Button
          android:id="@+id/btnBack"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_gravity="center_horizontal"
          android:layout_marginBottom="8dp"
          android:layout_marginTop="8dp"
          android:background="@color/colorPrimary"
          android:padding="8dp"
          android:text="@string/back"
          android:textColor="#ffffff"
          android:textSize="16sp" />
  </LinearLayout>

</LinearLayout>

نحوه نمایش این قالب به شکل زیر هست:

[attachment=654]

البته از دو بخش بالایی و پایینی فقط در هر لحظه یکی رو توی اکتیویتی نشون میدیم. دیگه توضیح لازم نیست که مقادیری که بصورت string@ تعریف شدن رو باید توی فایل strings.xml تعریف کنید.
مرحله چهارم، کلاس WebService

وظیفه این کلاس، اتصال به سرور وب و ارسال پارامترها برای اون هست. با کمک این کلاس میتونیم اطلاعات رو برای سرور بفرستیم و نتایج رو هم ازش دریافت کنیم:
public class Webservice {
    public static String read(HashMap<String, String> params) {
        String urlString = "http://www.ncis.ir/webservice.php";
        if (!params.isEmpty()) {
            urlString += "?";
            for (String key : params.keySet()) {
                urlString += key + "=" + Uri.encode(params.get(key)) + "&";
            }
        }
        final String finalUrlString = urlString.substring(0, urlString.length() - 1);
        final String[] result = new String[1];
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL(finalUrlString);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setDoInput(true);
                    connection.setDoOutput(true);
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(10000);
                    connection.connect();
                    InputStream inputStream = connection.getInputStream();

                    result[0] = convertInputStreamToString(inputStream);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        while (thread.isAlive()) ;
        return result[0];
    }
    private static String convertInputStreamToString(InputStream inputStream) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuilder builder = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
            return builder.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

همونطور که می‌بینید، این کلاس با اتصال به آدرس فرضی http://www.ncis.ir/webservice.php و ارسال پارامترها بصورت Get کار می‌کنه.
مرحله پنجم، ثبت نام کاربر

برای ثبت نام، از کلاس AsyncTask استفاده میکنیم تا ارتباط با سرور بصورت پشت پرده انجام بشه و برنامه توی مدت‌زمانی که منتظریم از سمت سرور جواب بیاد، هنگ نکنه:

public class AsyncRegister extends AsyncTask<String, String, Boolean> {
    private ProgressDialog progressDialog;
    private Runnable postExecute;

    protected void onPreExecute() {
        super.onPreExecute();
        progressDialog = new ProgressDialog(App.currentActivity);
        progressDialog.setIcon(R.mipmap.logo);
        progressDialog.setTitle(R.string.register_title);
        progressDialog.setMessage(App.context.getString(R.string.please_wait));
        progressDialog.show();
    }

    @Override
    protected Boolean doInBackground(String... strings) {
        int userId = register(strings[0], strings[1]);
        if (userId > 0) {
            // store userId in SharedPreferences for future logins
            return true;
        }
        return false;
    }

    public AsyncRegister setPostExecute(Runnable postExecute) {
        this.postExecute = postExecute;
        return this;
    }

    @Override
    protected void onPostExecute(Boolean result) {
        super.onPostExecute(result);
        progressDialog.dismiss();
        if (!result) {
            postExecute.run();
        }
    }

    private int register(String name, String mobile) {
        int result = 0;
        HashMap<String, String> params = new HashMap<>();
        params.put("action", "register");
        params.put("mobile", mobile);
        params.put("name", name);
        String json = Webservice.read(params);
        if (json != null) {
            try {
                JSONObject obj = new JSONObject(json);
                int code = obj.getInt("code");
                if (code == 1) {
                    result = Integer.parseInt(obj.getString("data"));
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return result;
    }
}

خوب اینجا خیلی مهمه که وب‌سرویس سمت سرور بعد از دریافت موبایل و اسم کاربر، یه رکورد براش توی دیتابیس ایجاد کنه و یه رمز تصادفی هم تولید کنه و همون رمز رو برای شماره موبایلی که براش فرستادیم، با اتصال به API سامانه پیامک، ارسال کنه. این موضوع رو توضیح نمیدم چون ارتباطی به اندروید نداره و بسته به اینکه وب‌سرویس سمت سرور رو با چه زبانی مینویسین میتونه متفاوت باشه. فقط خروجی که وب‌سرویس میده باید یه آرایه بصورت JSON باشه. اگه کاربر با موفقیت ایجاد شد، این ساختار برگردونده میشه:
{"code": 1, "data": 5}

که این عدد 5 یعنی id اون کاربر که توی جدول درج شده. اما اگه موفق به ثبت نام نشیم، وب‌سرویس این نتیجه رو برمیگردونه:
{"code": 0}

برای اینکه یه کاربر نتونه با یه موبایل، دوبار ثبت‌نام کنه هم میتونید سمت سرور چک کنید اگه موبایل تکراری بود، واسه همون رکورد یه رمز جدید ثبت کنید و دوباره id همون رکورد رو برگردونید. اینطوری کاربر توی گوشی قبلی از برنامه میفته بیرون (البته با مکانیزمی که در ادامه برای لاگین مینویسیم).

دقت کنید که توی شرط if (userId > 0} { داریم میگیم اگه سرور توی متد register عددی بزرگتر از صفر برگردوند یعنی ثبت‌نام با موفقیت انجام شده و باید این عدد رو برای لاگینهای بعدی توی SharedPreferences ذخیره کنیم.
مرحله ششم، ورود کاربر

برای ورود کاربر، یه کلاس AsyncTask دیگه مینویسیم که نام کاربری و رمز عبور دریافتی از کاربر رو با سرور مطابقت میده و نتیجه رو اعلام میکنه:

public class AsyncLogin extends AsyncTask<String, String, Boolean> {
    private ProgressDialog progressDialog;
    private Runnable postExecute;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        progressDialog = new ProgressDialog(App.currentActivity);
        progressDialog.setIcon(R.mipmap.logo);
        progressDialog.setTitle(R.string.login_title);
        progressDialog.setMessage(App.context.getString(R.string.please_wait));
        progressDialog.show();
    }

    @Override
    protected Boolean doInBackground(String... strings) {
        int userId = checkLogin(strings[0], strings[1]);
        // check userId with stores userId in SharedPreferences after register (replace 0 with the code stored in SP)
        if (userId == 0) {
            return true;
        }
        return false;
    }

    public AsyncLogin setPostExecute(Runnable postExecute) {
        this.postExecute = postExecute;
        return this;
    }

    @Override
    protected void onPostExecute(Boolean result) {
        super.onPostExecute(result);
        progressDialog.dismiss();
        if (result) {
            postExecute.run();
        }
    }

    private int checkLogin(String mobile, String password) {
        int result = 0;
        HashMap<String, String> params = new HashMap<>();
        params.put("action", "login");
        params.put("mobile", mobile);
        params.put("password", password);
        String json = Webservice.read(params);
        if (json != null) {
            try {
                JSONObject obj = new JSONObject(json);
                int code = obj.getInt("code");
                if (code == 1) {
                    result = Integer.parseInt(obj.getString("data"));
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return result;
    }
}

همونطور که میبینید، توی کلاسهای AsyncTask خودمون، توی onPreExecute یه ProgressDialog با آیکن برنامه و متن و عنوانی که توی فایل strings.xml تعریف می‌کنیم، نمایش داده میشه تا کاربر، تا زمانی که نتایج از سرور دریافت میشه، یکم سرگرم بشه.

توی doInBackground متن اول و دومی که موقع صدازدن این کلاس Async براش ارسال میشه، به متد checkLogin پاس داده میشه و خروجی اون توی متغیر userId قرار میگیره. درواقع وب‌سرویس ما در سمت سرور باید بعد از اینکه نام کاربری و موبایل رو چک کرد و رکورد مربوطه رو پیدا کرد، درصورتی که کاربر پیدا شد، مثل ساختار مرحله قبل نتیجه رو اعلام کنه و اگه پیدا نشد هم کد 0 رو برگردونه.

دقت کنید که توی شرط if چک میکنیم اگه userId که سرور برگردونده با اون چیزی که توی SharedPreferences توی مرحله قبل ذخیره کردیم برابر بود، اونوقت معناش اینه که کاربر رمز رو درسته زده و لاگین با موفقیت باید انجام بشه.
مرحله هفتم، سرویس دریافت‌کننده پیامک

این قسمت درواقع قلب برنامه ما محسوب میشه. جایی که پیامک دریافت میشه:

public class SmsReceiver extends BroadcastReceiver {

    private OnSmsReceivedListener listener;
    private EditText editText;

    public SmsReceiver(OnSmsReceivedListener listener, EditText editText) {
        this.listener = listener;
        this.editText = editText;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String message = "";
        String sender = "";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            SmsMessage sms = Telephony.Sms.Intents.getMessagesFromIntent(intent)[0];
            message = sms.getMessageBody();
            sender = sms.getOriginatingAddress();
        } else {
            Bundle data = intent.getExtras();
            if (data != null) {
                Object[] pdus = (Object[]) data.get("pdus");
                for (Object pdu : pdus) {
                    SmsMessage sms = SmsMessage.createFromPdu((byte[]) pdu);
                    message = sms.getMessageBody();
                    sender = sms.getOriginatingAddress();
                }
            }
        }
        if (listener != null) {
            listener.onSmsReceiver(message, sender, editText);
        }
        if (sender.equals("+98**************") || sender.equals("**************") {
            abortBroadcast();
        }
    }
}

این کلاس توی متد onReceive خودش پیامک دریافتی رو برحسب اینکه از اندروید KitKat و بالاتر استفاده میشه یا نسخه‌های قبل از اون، توی متغیرهای message و sender ذخیره میکنه و بعد اگه شنونده رویداد (listener) تعریف شده بود، متد onSmsReceiver اون رو صدا میزنه و متن و شماره و کادر متن نمایش کد دریافتی رو براش میفرسته تا رمزی که ازطرف سرور بصورت پیامک ارسال شده، توی کادر متن مربوطه بطور خودکار نوشته بشه (البته اینکه داخل کادر نوشته بشه رو بعداً می‌نویسیم).

در انتها هم اگه شماره فرستنده، با شماره سامانه پیامک ما برابر بود، با فراخوانی abortBroadcast جلوی دریافتش توی Inbox گوشی رو میگیره (توی بعضی موبایل‌ها جواب نمیده).
مرحله هشتم، جمع‌بندی ابزارهای ساخته‌شده در کلاس اکتیویتی لاگین

خوب حالا وقتشه که از این ابزارهایی که ساختیم، توی اکتیویتی لاگین استفاده کنیم:

public class LoginActivity extends ActivityEnhanced {
    private Button btnActivate;
    private Button btnHaveCode;
    private Button btnBack;
    private Button btnSend;
    private EditText edtCode;
    private EditText edtMobile;
    private EditText edtName;
    private SmsReceiver smsReceiver;
    private TextView txtCode;
    private TextView txtName;
    private TextView txtMobile;
    private TextView txtWaiting;
    private ViewGroup lytActivate;
    private ViewGroup lytSend;

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

        getControls();

        smsReceiver = new SmsReceiver(new OnSmsReceivedListener() {
            @Override
            public void onSmsReceiver(String message, String phone, EditText editText) {
                if (phone.equals("+98**************") || phone.equals("**************") {
                    editText.setText(message);
                }
            }
        }, edtCode);

        registerReceiver(smsReceiver, new IntentFilter("android.provider.Telephony.SMS_RECEIVED"));

        lytActivate.setVisibility(View.GONE);

        btnActivate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String mobile = edtMobile.getText().toString().replaceAll("[^0-9]", "");
                mobile = mobile.substring(mobile.length() - 9);
                new AsyncLogin()
                        .setPostExecute(new Runnable() {
                            @Override
                            public void run() {
                                Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                                LoginActivity.this.startActivity(intent);
                                LoginActivity.this.finish();
                                unregisterReceiver(smsReceiver);
                            }
                        })
                        .execute(mobile, edtCode.getText().toString());
            }
        });

        btnBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                lytActivate.setVisibility(View.GONE);
                lytSend.setVisibility(View.VISIBLE);
            }
        });

        btnHaveCode.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (edtMobile.getText().toString().trim().isEmpty()) {
                    Toast.makeText(LoginActivity.this, "شماره موبایل اجباری است", Toast.LENGTH_SHORT).show();
                } else {
                    lytActivate.setVisibility(View.VISIBLE);
                    lytSend.setVisibility(View.GONE);
                }
            }
        });

        btnSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String name = edtName.getText().toString();
                String mobile = edtMobile.getText().toString().replaceAll("[^0-9]", "");
                mobile = mobile.substring(mobile.length() - 9);
                if (name.length() > 0 && mobile.length() > 0) {
                    lytActivate.setVisibility(View.VISIBLE);
                    lytSend.setVisibility(View.GONE);
                    new AsyncRegister()
                            .setPostExecute(new Runnable() {
                                @Override
                                public void run() {
                                    lytActivate.setVisibility(View.GONE);
                                    lytSend.setVisibility(View.VISIBLE);
                                    Toast.makeText(LoginActivity.this, "در زمان ثبت نام خطایی رخ داد. سعی مجدد", Toast.LENGTH_SHORT).show();
                                }
                            }).execute(name, mobile);
                } else {
                    Toast.makeText(LoginActivity.this, "نام و تلفن را وارد کنید.", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    private void getControls() {
        btnActivate = (Button) findViewById(R.id.btnActivate);
        btnHaveCode = (Button) findViewById(R.id.btnHaveCode);
        btnBack = (Button) findViewById(R.id.btnBack);
        btnSend = (Button) findViewById(R.id.btnSend);
        edtCode = (EditText) findViewById(R.id.edtCode);
        edtMobile = (EditText) findViewById(R.id.edtMobile);
        edtName = (EditText) findViewById(R.id.edtName);
        lytActivate = (ViewGroup) findViewById(R.id.lytActivate);
        lytSend = (ViewGroup) findViewById(R.id.lytSend);
        txtCode = (TextView) findViewById(R.id.txtCode);
        txtName = (TextView) findViewById(R.id.txtName);
        txtMobile = (TextView) findViewById(R.id.txtMobile);
        txtWaiting = (TextView) findViewById(R.id.txtWaiting);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (smsReceiver != null) {
            try {
                unregisterReceiver(smsReceiver);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }
        }
    }
}

خوب توی این کلاس، ابتدا با فراخوانی متد getControls عناصر موجود توی لی‌اوت رو دریافت می‌کنیم. بعد یه شئ جدید از کلاس SmsReceiver که تو مرحله هفتم ساختیم ایجاد می‌کنیم و بعنوان پارامترهاش، یک شئ جدید از رابط OnSmsReceivedListener که توی مرحله دوم ساختیم و همچنین کادر متنی که کد دریافتی ازطریق پیامک باید اونجا وارد بشه رو می‌فرستیم.

توی رابط هم گفتیم که اگه شماره ارسال‌کننده با شماره سامانه پیامک ما برابر بود، توی کادر متن اون رو بنویسه.

توی خط بعدی این دریافت‌کننده رو برای فیلتر اینتنت android.provider.Telephony.SMS_RECEIVED ثبت میکنیم تا اگه پیامکی اومد، اجرا بشه.

بعد نمای فعالسازی (نیمه دوم لی‌اوتی که توی مرحله سوم ساختیم) رو مخفی میکنیم تا فقط بخش مربوط به ورود نام و نام خانوادگی و شماره موبایل دیده بشه.

بعد میگیم اگه دکمه فعالسازی فشار داده شد، شماره موبایل رو بگیره و همراه با متن کد واردشده، برای کلاس AsyncLogin که توی مرحله ششم ساختیم ارسال کنه و بعد از لاگین موفقیت‌آمیز هم به اکتیویتی Main منتقل بشه و شنونده پیامک رو هم غیرفعال کنه تا دیگه به پیامکهای دریافتی گوش نده. اگه به کد کلاس AsyncLogin دقت کنید، درصورتی که نتیجه result برابر با true باشه این کد رو اجرا میکنه.

دکمه Back خیلی ساده است و دوباره نمایش ورود نام و موبایل رو نشون میده و نیمه دوم صفحه رو مخفی میکنه.

دکمه HaveCode هم چک میکنه اگه کاربر موبایل رو خالی گذاشته باشه بهش میگه باید وارد کنی و اگه خالی نباشه، نیمه اول رو مخفی میکنه و نیمه ورود کد فعالسازی رو نشون میده.

دکمه Send هم اسم کاربر و شماره موبایل رو برای کلاس AsyncRegister میفرسته. البته کدی رو هم تعریف میکنه که درصورت لاگین موفقیت‌آمیز باید اجرا بشه که توی اون کد، نیمه دوم (ورود رمز دریافتی ازطریق پیامک) ظاهر میشه و نیمه اول صفحه رو پنهان میکنه. کدی هم که بعنوان postExecute معرفی میکنه برای وقتی هست که کد فعالسازی با موفقیت ارسال نشه (ثبت‌نام موفقیت‌آمیز نباشه). اگه به کلاس AsyncRegister دقت کنید که توی مرحله پنجم نوشتیم، این کد درصورتی اجرا میشه که نتیجه result برابر با false باشه.
امیدوارم این آموزش برای شما عزیزان مفید واقع شده باشه. اگه هرجای مطالب فوق سؤال یا مشکلی بود، خوشحال میشم در میون بگذارین.