본문 바로가기
Framework & Lib & API/API

[파이어베이스] 안드로이드 HttpsURLConnection을 이용하여 웹서버에 토큰 전달

by 코딩공장공장장 2020. 12. 4.

-웹서버에 토큰 보내는 방법

[Android] MainActivity.java

 @Override
    protected void onStop() {
        FirebaseInstanceId.getInstance().getInstanceId()
                .addOnCompleteListener(new OnCompleteListener<InstanceIdResult>(){
                    @Override
                    public void onComplete(@NonNull Task<InstanceIdResult> task) {
                        String token = task.getResult().getToken();
                        String returnToken ="";
                       
                        try {
                            HttpTask httpTask = new HttpTask();
                            httpTask.execute("https://서버로 요청할 url", token).get();
                            String jsonResult = httpTask.getToken();
                            JSONObject jObject = null;
                            jObject = new JSONObject(jsonResult);
                            returnToken = jObject.getString("token");
                        }catch (JSONException e) {
                            e.printStackTrace();
                        } catch (ExecutionException e) {
                            e.printStackTrace();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });

        super.onStop();
    }

 

onStop()메소드에서 HttpsUrlConnection을 이용해 웹서버에 토큰을 함께 보내주었습니다.

 

토큰은 주기적으로 웹서버에 보내 업데이트 할 필요가 있으니 

 

activity가 안보이는 onStop()메소드가 실행될때마다 비동기방식으로 웹서버에 보냈습니다. 

 

저기서 중요한 것은 구글링에 나와있는 많은 소스들이 

 

FirebaseInstanceId.getInstance().getToken().toString() 이 코드를 통해 토큰을 얻어내고 있는데

 

이는 안드로이드에서 권장하지 않고 deprecated된 메소드입니다. 

 

언젠가 사라질수 있으니 저와 같이 파이어베이스 인스턴스를 구해 리스너 안해 토큰을 얻어 필요한 부분을 

 

구현하시기를 추천합니다.

 

 

[Android]  HttpTask.java

public class HttpTask extends AsyncTask<String, Void, String> {

    String result;
    @Override
    protected String doInBackground(String... params){
        HttpsURLConnection urlConnection= null;
        java.net.URL url = null;
        String response = "";

        try {
            result=null;
            url  = new java.net.URL(params[0]);
            urlConnection=(HttpsURLConnection)url.openConnection();

            String cookieString = CookieManager.getInstance().getCookie("https://웹서버 url.com");
            if (cookieString != null) {
                urlConnection.setRequestProperty("Cookie", cookieString);
            }
            String token = params[1];
            urlConnection.setRequestMethod("POST");
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.connect();

            //
            OutputStream outputStream = urlConnection.getOutputStream();
            outputStream.write(token.getBytes("UTF-8")); //전송할 데이터가 저장된 변수를 이곳에 입력합니다.

            outputStream.flush();
            outputStream.close();


            int resCode = urlConnection.getResponseCode();


            if (resCode == 200){
                InputStream inStream = null;
                inStream = urlConnection.getInputStream();
                BufferedReader bReader = new BufferedReader(new InputStreamReader(inStream));
                String temp = "";
                while((temp = bReader.readLine()) != null){
                    response += temp;
                }
                bReader.close();
                inStream.close();
                result = response;
            } else {
                result = "없음";
            }

            urlConnection.disconnect();

        } catch (Exception e) {
            e.printStackTrace();
            result = "없음";
        }
        return result;
    }

    @Override
    protected void onPostExecute(String s) {

        super.onPostExecute(s);
        //파일 없을 경우 처리
        if(result.equals("")){
            //파일 없을경우
        } else {
            //파일 있을경우
        }
    }


    public String getToken(){
        return result;
    }
}

코드에 대해 이해와 개념에 대한 이해가 필요할 부분에 대해 몇가지만 간단히 설명드리겠습니다.

 

HttpTask클래스가 상속 받은  AsyncTask<>는 비동기 작업을 할 수 있는 쓰레드를 지원합니다. 

 

안드로이드는 메인쓰레드에서 UI를 구현하고 초기앱을 구현하는데 필요한 작업을 합니다. 

 

네트워크 등의 시간이 소요되는 작업은 비동기로 작업하는것을 추천합니다.

 

이를 수행할 수 있는 클래스가 AsyncTask 입니다.  

 

doInBackground()메소드는 메인쓰레드 이외의 별도의 쓰레드가 실행되면서 호출되는 함수로 

 

우리가 구현해야할 작업을 하는 메소드입니다. 메인액티비티에서 excute함수를 호출하면서 실행이 됩니다.

 

이 결과를 onPostExecute(String s)메소드의 파라미터로 전달합니다.

 

왠만한 소스는 한줄한줄 영어뜻만 해석하더라도 어떤 작업을 하는지 이해할수 있을거라 생각됩니다.

 

소스중에 params[0], params[1]이라는 파라미터가 보일 것입니다.

 

이는 MainActivity에서 httpTask.execute("https://웹서버로 요청할 url", token).get(); 

 

execute 메소드를 실행할때 넘겨준 첫번째 인자가 params[0], params[1] 입니다. 

 

doInBackground가 가변인자를 받으므로 저렇게 사용하는 것입니다.

 

setRequestProperty("Cookie", cookieString)로 쿠키 설정을 한 것이고

 

웹서버에서 세션을 사용하기 위해 사용한 한것입니다. 

(저는 웹서버에서 세션을 이용해서 하는 작업이 있어서요.)

 

OutputStream으로 보낼때 byte타입으로 보내기 때문에 서버에서 다시 디코딩 해야할 필요가 있습니다.

 

 int resCode = urlConnection.getResponseCode(); 이 코드는 서버에서 리턴받은 상태값입니다. 

 

서버의 페이지를 찾을수 없을때는 404, 서버 내부 오류는 500 등 서버에서 작동을 제대로 처리하고 

 

리턴을 받았는지 확인하기 위한 코드입니다. 정상적으로 작동하고 리턴받았다면 200이 리턴됩니다.

 

 

 

[스프링 웹서버] 컨트롤러

@RequestMapping("요청URL")
	@ResponseBody
	public Map<String, String> giveToAndroid(@RequestBody byte buffers[],HttpServletRequest request,HttpSession session) throws Exception{
		String configLocation = "classpath:applicationContext.xml";
		AbstractApplicationContext ctx = new GenericXmlApplicationContext(
				configLocation);
		TokenRegisterService tokenRegisterService = ctx.getBean("tokenRegisterService", TokenRegisterService.class );
		String email = (String)session.getAttribute("email");
		String token = new String(buffers,"UTF-8");
		token = URLDecoder.decode(token,"UTF-8");
		token = token.substring(0, token.length()-1);
		
		String status = tokenRegisterService.registerAndroidToken(email, token);
		ctx.close();
		
		HashMap<String, String> map = new HashMap<>();
		map.put("token", token);
		logger.info(token);
		
		return map;
	}

 

 

저의 웹서버에서는 email값이 고유값이기 때문에 DB에 email과 함께 디바이스 토큰을 저장해주었습니다. 

 

위의 소스를 보면 안드로이드로 부터 받은 토큰값을 new String(token, "UTF-8" )로 한번 

 

URLDecoder로 한번, 총 두번 디코딩 한것을 볼 수 있는데요. 

 

안드로이드에서 보낸 토큰 값을 그대로 사용하려고 했는데 이상하게 특수문자 부분이 다르게 치환되어 

 

검색을 해보니 url 디코딩을 해주어야 하는 부분이더라고요. 

 

이부분때문에 꽤나 고생했습니다. url디코딩 꼭 해주시고요. 

 

그리고 토큰 마직막에 =(등호)가 항상 붙어 있길래 마지막글자 제외 시켜줬습니다. 

 

로그 찍어 확인해보시면 저와 같은 현상을 확인할 수 있을 것입니다. 

 

나머지 서비스클래스를 통해 구현하는 부분은 생략하겠습니다.(각자 자신의 웹서버에 맞게 구현해주면 될것입니다.)

 

 

 

참고로 AndroidManifest.xml에서

 

<uses-permission android:name="android.permission.INTERNET" />

 

인터넷 사용 허용해주세요.

반응형