-웹서버에 토큰 보내는 방법
[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" />
인터넷 사용 허용해주세요.
'Framework & Lib & API > API' 카테고리의 다른 글
[FCM]Firebase(파이어베이스)와 스프링 연동(토큰방식 여러개 한번에 푸시알림 보내기) (0) | 2020.12.21 |
---|---|
[파이어베이스] 안드로이드 웹뷰 푸시알림으로 특정 링크로 접속하도록 구현 (0) | 2020.12.06 |