728x90

Eclipse 에서 만든 코드를 Android Studio 로 변환하고 나서 신규로 코드를 추가하면 문제가 생긴다.

FCM 을 이용한 메시지 발송시 메시지 수신하는 걸 해결하지 못한 상태다.

FCM 메시지 발송을 위한 TokenID 를 회원DB에 저장하는 방법을 Login.java 코드를 이용하여 구현했다.


Login.java 파일에서 로그인 정보를 입력하고 확인을 누르면,  POST 방식으로 서버에 있는 loginChk.php 파일로 전송되어 내용을 확인하고 정보를 기록하고 결과값을 반환한다.

서버에서 결과값은 echo 문을 다시 안드로드이드폰에서 받아서 그 결과값을 기준으로 로그인 성공, 로그인 실패, 인증된 단말인지 여부 체크 등을 한다.


사용자 기기 토큰 정보를 획득하는 코드는 http://blog.naver.com/PostView.nhn?blogId=cosmosjs&logNo=220739141098&categoryNo=0&parentCategoryNo=56&viewDate=&currentPage=1&postListTopCurrentPage=1&from=search 를 참조하면서 해보는 중이다.


=== Login.java ====

package com.tistory.link2me.addresschart;

import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

import com.google.firebase.iid.FirebaseInstanceId;

import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;

import java.util.ArrayList;
import java.util.List;

public class Login extends Activity {

    String getDeviceID; // 스마트기기의 장치 고유값
    ProgressDialog dialog = null;
    EditText etId;
    EditText etPw;

    String loginID;
    String loginPW;
    CheckBox autologin;
    Boolean loginChecked;
    List<NameValuePair> params;
    public SharedPreferences settings;
    CookieManager cookieManager;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.login);

        // ActionBar 제거하기
        ActionBar actionbar = getActionBar();
        actionbar.hide();

        // 네트워크 연결상태 체크
        if(NetworkConnection() == false){
            NotConnected_showAlert();
        }

        etId = (EditText) findViewById(R.id.login_id_edit);
        etPw = (EditText) findViewById(R.id.login_pw_edit);
        autologin = (CheckBox) findViewById(R.id.autologinchk);

        settings = getSharedPreferences("settings", Activity.MODE_PRIVATE);
        loginChecked = settings.getBoolean("LoginChecked", false);
        if (loginChecked) {
            etId.setText(settings.getString("loginID", ""));
            etPw.setText(settings.getString("loginPW", ""));
            autologin.setChecked(true);
        }

        if(!settings.getString("loginID", "").equals("")) etPw.requestFocus();

        CookieSyncManager.createInstance(this);
        cookieManager = CookieManager.getInstance();
        CookieSyncManager.getInstance().startSync();

        Button submit = (Button) findViewById(R.id.login_btn);
        submit.setOnClickListener(new Button.OnClickListener(){

            @Override
            public void onClick(View v) {
                dialog = ProgressDialog.show(Login.this, "", "Validating user...", true);
                 new Thread(new Runnable() {
                        public void run() {
                            login();
                        }

                      }).start();
            }

        });

    }

    void login() {
        try {
            loginID = etId.getText().toString().trim();
            loginPW = etPw.getText().toString().trim();

            // 단말기의 ID 정보를 얻기 위해서는 READ_PHONE_STATE 권한이 필요
            TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
            if (mTelephony.getDeviceId() != null){
                getDeviceID = mTelephony.getDeviceId();  // 스마트폰 기기 정보
            } else {
                getDeviceID = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID);
            }

            // 사용자 기기의 고유 토큰 정보를 획득
            String getToken = FirebaseInstanceId.getInstance().getToken();

            String postURL = Value.IPADDRESS + "/loginChk.php";
            HttpPost post = new HttpPost(postURL);

            // 전달할 인자들
            params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("loginID", loginID));
            params.add(new BasicNameValuePair("loginPW", loginPW));
            params.add(new BasicNameValuePair("deviceID", getDeviceID));
            params.add(new BasicNameValuePair("tokenID", getToken));

            UrlEncodedFormEntity ent = new UrlEncodedFormEntity(params,HTTP.UTF_8);
            post.setEntity(ent);

            HttpClient httpclient = new DefaultHttpClient();

            ResponseHandler<String> responseHandler = new BasicResponseHandler();
            final String responsePost = httpclient.execute(post, responseHandler);

            System.out.println("DeviceID : " + getDeviceID);
            System.out.println("Login Token : " + getToken);
            System.out.println("Response : " + responsePost);

            runOnUiThread(new Runnable() {
                public void run() {
                    dialog.dismiss();
                }
            });

            if(responsePost.equalsIgnoreCase("1")){ // 로그인 정보 일치
                runOnUiThread(new Runnable() {
                    public void run() {
                        Toast.makeText(Login.this,"Login Success", Toast.LENGTH_SHORT).show();
                    }
                });

                // 쿠키 정보 생성을 통한 PHP 세션 접속 유지 처리
                List<Cookie> cookies = ((DefaultHttpClient)httpclient).getCookieStore().getCookies();
                if (!cookies.isEmpty()) {
                    for (int i = 0; i < cookies.size(); i++) {
                        String cookieString = cookies.get(i).getName() + "="
                                    + cookies.get(i).getValue();
                        Log.e("PHP_setCookie", cookieString);
                        cookieManager.setCookie(Value.IPADDRESS, cookieString);
                    }
                }
                Thread.sleep(300);

                startActivity(new Intent(this.getApplicationContext(), MainActivity.class));
                finish(); // finish()를 호출해서 Activity를 없애줌

            } else if(responsePost.equalsIgnoreCase("-1")){ // 등록된 단말기와 불일치
                deviceDismatch_showAlert();
            } else {
                showAlert();
            }
        } catch(Exception e) {
            dialog.dismiss();
            System.out.println("Exception : " + e.getMessage());
        }

    }

    public void onStop(){
        // 어플리케이션이 화면에서 사라질때
        super.onStop();
        // 자동 로그인이 체크되어 있고, 로그인에 성공했으면 폰에 자동로그인 정보 저장
        if (autologin.isChecked()) {
            settings = getSharedPreferences("settings",Activity.MODE_PRIVATE);
            SharedPreferences.Editor editor = settings.edit();

             editor.putString("loginID", loginID);
             editor.putString("loginPW", loginPW);
             editor.putBoolean("LoginChecked", true);

             editor.commit();
        } else {
            // 자동 로그인 체크가 해제되면 폰에 저장된 정보 모두 삭제
            settings = getSharedPreferences("settings", Activity.MODE_PRIVATE);
            SharedPreferences.Editor editor = settings.edit();
            editor.clear(); // 모든 정보 삭제
            editor.commit();
        }

    }

    public void deviceDismatch_showAlert(){
        Login.this.runOnUiThread(new Runnable() {
            public void run() {
                AlertDialog.Builder builder = new AlertDialog.Builder(Login.this);
                builder.setTitle("등록단말 불일치");
                builder.setMessage("최초 등록된 단말기가 아닙니다.\n" + "관리자에게 문의하여 단말기 변경신청을 하시기 바랍니다.")
                       .setCancelable(false)
                       .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                           public void onClick(DialogInterface dialog, int id) {
                           }
                       });
                AlertDialog alert = builder.create();
                alert.show();
            }
        });
    }

    public void showAlert(){
        Login.this.runOnUiThread(new Runnable() {
            public void run() {
                AlertDialog.Builder builder = new AlertDialog.Builder(Login.this);
                builder.setTitle("로그인 에러");
                builder.setMessage("로그인 정보가 일치하지 않습니다.")
                       .setCancelable(false)
                       .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                           public void onClick(DialogInterface dialog, int id) {
                           }
                       });
                AlertDialog alert = builder.create();
                alert.show();
            }
        });
    }

    private void NotConnected_showAlert() {
        AlertDialog.Builder builder = new AlertDialog.Builder(Login.this);
        builder.setTitle("네트워크 연결 오류");
        builder.setMessage("사용 가능한 무선네트워크가 없습니다.\n" + "먼저 무선네트워크 연결상태를 확인해 주세요.")
               .setCancelable(false)
               .setPositiveButton("확인", new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       finish(); // exit
                        //application 프로세스를 강제 종료
                        android.os.Process.killProcess(android.os.Process.myPid() );
                   }
               });
        AlertDialog alert = builder.create();
        alert.show();

    }

    private boolean NetworkConnection() {
        ConnectivityManager manager = (ConnectivityManager) getSystemService (Context.CONNECTIVITY_SERVICE);
        boolean isMobileAvailable = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).isAvailable();
        boolean isMobileConnect = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).isConnectedOrConnecting();
        boolean isWifiAvailable = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isAvailable();
        boolean isWifiConnect = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnectedOrConnecting();

        if ((isWifiAvailable && isWifiConnect) || (isMobileAvailable && isMobileConnect)){
            return true;
        }else{
            return false;
        }
    }

    // Back 버튼을 누르면 어플 종료여부 확인 처리
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if( keyCode == KeyEvent.KEYCODE_BACK ) {
            new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert).setTitle("Quit").setMessage("어플을 종료하시겠습니까?").setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                @Override
                public void onClick( DialogInterface dialog, int which) {
                    moveTaskToBack(true); // 본Activity finish후 다른 Activity가 뜨는 걸 방지.
                    finish();
                    //application 프로세스를 강제 종료
                    android.os.Process.killProcess(android.os.Process.myPid() );
                }
        }).setNegativeButton( "No", null ).show();

        return true;
      }

      return super.onKeyDown(keyCode, event);
     }

    @Override
    protected void onResume()
    {
        super.onResume();
        CookieSyncManager.getInstance().startSync();
    }

    @Override
    protected void onPause()
    {
        super.onPause();
        CookieSyncManager.getInstance().stopSync(); // 동기화 종료
    }
}
 


이제 MySQL DB 및 PHP 코드를 구현해야 한다.

MySQL DB에는 tokenID 칼럼을 추가한다. Varchar(200) 으로 길이를 설정해준다. 토콘의 길이가 상당히 길더라.

테스트하는 회원 테이블은 회원ID와 회원 Data 를 분리하여 저장하는 방식으로 만들어보고 있다.


테이블 구조

CREATE TABLE IF NOT EXISTS `member_id` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `site` int(11) NOT NULL DEFAULT '0',
  `id` varchar(50) NOT NULL DEFAULT '',
  `pw` varchar(50) NOT NULL DEFAULT '',
  `code` int(6) NOT NULL DEFAULT '0',
  `admin` int(2) NOT NULL DEFAULT '0',
  PRIMARY KEY (`uid`),
  UNIQUE KEY `id` (`id`),
  KEY `code` (`code`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;


CREATE TABLE IF NOT EXISTS `member_data` (
  `memberuid` int(11) NOT NULL,
  `site` int(11) NOT NULL DEFAULT '0',
  `auth` tinyint(4) NOT NULL DEFAULT '0',
  `level` int(11) NOT NULL DEFAULT '0',
  `admin` tinyint(4) NOT NULL DEFAULT '0',
  `email` varchar(50) NOT NULL DEFAULT '',
  `name` varchar(30) NOT NULL DEFAULT '',
  `nic` varchar(50) NOT NULL DEFAULT '',
  `grade` varchar(20) NOT NULL DEFAULT '',
  `photo` varchar(200) NOT NULL DEFAULT '',
  `sex` tinyint(4) NOT NULL DEFAULT '0',
  `officeNO` varchar(14) NOT NULL DEFAULT '',
  `mobileNO` varchar(14) NOT NULL DEFAULT '',
  `num_login` int(11) NOT NULL DEFAULT '0',
  `d_regis` varchar(14) NOT NULL DEFAULT '',
  `tokenID` varchar(200) DEFAULT NULL,
  `phoneID` varchar(60) DEFAULT NULL,
  PRIMARY KEY (`memberuid`),
  KEY `site` (`site`),
  KEY `auth` (`auth`),
  KEY `level` (`level`),
  KEY `admin` (`admin`),
  KEY `email` (`email`),
  KEY `name` (`name`),
  KEY `nic` (`nic`),
  KEY `sex` (`sex`),
  KEY `d_regis` (`d_regis`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 



=== loginChk.php ===

<?php
if(!isset($_SESSION)) {
    session_start();
}

@extract($_POST); // POST 전송으로 전달받은 값 처리
if(isset($loginID) && !empty($loginID) && isset($loginPW) && !empty($loginPW)) {

    $deviceID = $deviceID ? $deviceID : '';

    if(empty($deviceID)){
        require_once 'dbconnect.php'; // db접속
        require_once 'phpclass/loginClass.php';

        $c=new LoginClass();

        $row = $c->WebUserAuthCheck($loginID,$loginPW);
        if(is_array($row)) {
            if($row['code'] > 0) {
                $_SESSION['userID'] = $row['id'];
                $_SESSION['userPW'] = md5($loginPW);
                $_SESSION['code'] = $row['code'];
                $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
                $_SESSION['ua'] = $_SERVER['HTTP_USER_AGENT'];

                echo("<meta http-equiv='Refresh' content='0; URL=m/list.php'>");
            } else {
                echo '권한 불가';
            }
        } else if($row == '0'){
            $msg ='정보가 올바르지 않습니다';
            echo "<script>alert('".$msg."');history.go(-1);</script>";
        } else {
            $msg ='정보가 올바르지 않습니다';
            echo "<script>alert('".$msg."');history.go(-1);</script>";
        }

    } else {
        require_once 'db.info.php';
        require_once 'phpclass/dbClass.php';
        $conn=new MySQLiDbClass();
        $dbconn = $conn->isConnectDb($DB); // 안드로이드폰에서는 반드시 객체로 생성해야 정상접속
        require_once 'phpclass/loginClass.php';
        $c=new LoginClass();

        $result = $c->MobileUserAuthCheck($loginID,$loginPW,$deviceID);
        if($result > 0 ) {
            session_save_path('./_tmp/session');

            $_SESSION['userID'] = $loginID;
            $_SESSION['userPW'] = md5($loginPW);
            $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
            $_SESSION['ua'] = $_SERVER['HTTP_USER_AGENT'];

            // 토큰 등록 및 갱신
            if(isset($tokenID) && strlen($tokenID) > 63){
                $c->registerToken($tokenID,$loginID,$deviceID); // DB에 토큰 저장
                //$myfile = fopen("tokenfile.txt", "a") or die("파일 쓰기를 할 수 없습니다.");
                //fwrite($myfile, $tokenID);
                //fclose($myfile);
            }
            echo 1;
        } else if($result == 0) {
            echo 0; // 로그인 정보 틀림
        } else {
            echo '-1'; // Phone mismatch
        }
    }

} else {
    echo("<meta http-equiv='Refresh' content='0; URL=loginForm.php'>");
}
?>
 

 // 토큰 등록 및 갱신(2017-03-24) 함수 만들기 (LoginClass.php 파일내에 존재)
    function registerToken($token,$userID,$deviceID){
        global $dbconn;
        $rs = $this->getDeviceChk($userID,$deviceID);
        if($rs > 0 ){
            $gettokenID = $this->getTokenIDChk($rs); // 0 또는 토큰 반환
            if(($gettokenID == '0') || ($gettokenID !== $token)){ // 등록되어 있지 않으면 등록
                $sql ="UPDATE member_data SET tokenID='".$token."'";
                $sql.=" where memberuid='".$rs."'";
                if($result = mysqli_query($dbconn,$sql)){
                    return 1;
                } else {
                    return 0;
                }
            }
        } else { // 장치 ID 와 다르거나 없으면
            // 로그인 금지
        }
    }

    function getTokenIDChk($rs){
        global $dbconn;
        $sql ="select tokenID from member_data where memberuid='".$rs."'";
        if($result = mysqli_query($dbconn,$sql)){
            $row = mysqli_fetch_row($result);
            if($row[0] == NULL){
                return 0;
            } else {
                return $row[0];
            }
        } else {
            return 0;
        }
    }

    function getDeviceChk($userID,$deviceID){
        global $dbconn;
        // 사용자 기준 장치 정보 검사
        $sql ="select count(phoneID),memberuid from member_data";
        $sql.=" where memberuid=(select uid from member_id where id='".$userID."') and phoneID='".$deviceID."'";
        if($result = mysqli_query($dbconn,$sql)){
            $row = mysqli_fetch_row($result);
            if($row[0] == 1){
                return $row[1]; // 있으면 memberuid 반환
            } else {
                return $row[0];
            }
        } else {
            return 0;
        }
    }


토큰을 회원 DB에 저장하는 코드 구현로직이 어떻게 되는지만 참고하면 된다고 본다.


FCM 을 이용한 PUSH 메시지 전송을 성공하면 다시 기록해 두련다.

블로그 이미지

Link2Me

,