[안드로이드] duplicate entry 에러 해결 방법



Error:Execution failed for task 에러를 해결하니 이번엔 중복에러가 나타났다



duplicate entry: com/google/zxing/aztec/AztecDetectorResult.class


이런 에러인데


AztecDetectorResult 클래스가 중복이 되었다 뭐 그런 이야기다



구글의 라이브러리를 이것저것 참조하다보면 저런 에러가 흔히 나타나는듯 하다.


나같은 경우는


QR코드를 읽는 라이브러리와


안드로이드 카메라로 촬영한 이미지의 문자를 인식하는 라이브러리를 사용하던 중에


이것저것 끌어오다가 나타난 에러였다.



어느부분에서 중복되었는지 찾기가 쉽지는 않지만


어차피 앞쪽의 경로를 보면 대충 사이즈는 나오니까 잘 찾아보도록 하자









안드로이드 스튜디오의 프로젝트보기로 (안드로이드 보기론 안보임)


저 두군데를 뒤져보면 중복되는 녀석들이 나타난다



단순히 build.gradle에서 컴파일 명령을 지우는 것 만으로는 해결이 되지 않기 때문에


직접 저기서 파일 자체를 삭제 해주어야 한다.



물론 아무거나 지우다 일어나는 일은 책임 못진다.



build.gradle에서 명령줄만 삭제 해보고 



정상 동작 한다면 그떄 지우고 APK파일로 구동시켜 보도록 하자.




단순히 빌드할땐 나타나지 않다가 APK파일로 생성할때 나타나는 에러니까


정상동작하는걸 확인 후 삭제하는 것으로 



저 에러를 해결 하자



[안드로이드] Error:Execution failed for task ':app:transformClassesWithDexForDebug'. 오류 해결 방법



신나게 코딩하고나서 모바일로 테스트 까지 다 해놓고


APK파일로 묶으려는데 저런 에러가 나서 당황스러운 경우가 있었다.



대체 뭐지.. 뭘까..


하고 뒤쪽의 에러를 더 봤더니



com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: 

com.android.dex.DexException: Multiple dex files define Lcom/google/zxing/BarcodeFormat;



이런 내용의 로그가 나타났고


저기서 잘 보아야 할것은


Multiple dex files define 


바로 이부분이었다


음... 뭐 다중 어쩌구 파일을 못찾겠다 뭐 이런건지


일단 잘 모르니까 검색을 해보니


역시나 스택오버플로우 형님들이 좋은 답변들을 알려주었다



안드로이드 build.gradle (app 레벨)에 들어가서


몇줄 추가해 주도록 하자


dependencies {
compile 'com.android.support:multidex:1.0.1'
}


디펜던시에서 저 한줄을 추가 해주고



android {

.......
defaultConfig {

.........
multiDexEnabled true
}

.....
}


저렇게 하나 추가해 주도록 하자



그리고 AdnroidManifest.xml에 가서


<application
.....
android:name="android.support.multidex.MultiDexApplication">

......
</application>


어플리케이션단에 추가를 해준다



그럼 해결이 된다!

[안드로이드] 기기의 카메라에 오류가 생겼습니다. 기기를 재시작해야할수도있습니다. 해결방법 






QR코드나 BAR코드 리딩 기능을 넣거나


OCR 문자 인식 관련해서 API 23 이상부터 나타나는 에러이다


해결방법은 간단하다


API23 이전엔 그냥 매니페스트에 권한요청만 하면 되었는데


API23 이후부터는 아얘 권한 요청 팝업을 띄워서


허용을 받아야 한다.


해결방법은 어디서 찾아다가 프로젝트에 적용시켰는데 어디서 본건지 기억이 잘 안난다;





해결 방법은 아래와 같다


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        /**********권한 요청************/
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            /**
             * 사용자 단말기의 권한 중 "카메라" 권한이 허용되어 있는지 확인한다.
             *  Android는 C언어 기반으로 만들어졌기 때문에 Boolean 타입보다 Int 타입을 사용한다.
             */
            int permissionResult = checkSelfPermission(Manifest.permission.CAMERA);
 
 
            /** * 패키지는 안드로이드 어플리케이션의 아이디이다. *
             *  현재 어플리케이션이 카메라에 대해 거부되어있는지 확인한다. */
            if (permissionResult == PackageManager.PERMISSION_DENIED) {
 
 
                /** * 사용자가 CALL_PHONE 권한을 거부한 적이 있는지 확인한다. *
                 * 거부한적이 있으면 True를 리턴하고 *
                 * 거부한적이 없으면 False를 리턴한다. */
                if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
                    AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
                    dialog.setTitle("권한이 필요합니다.").setMessage("이 기능을 사용하기 위해서는 단말기의 \"카메라\" 권한이 필요합니다. 계속 하시겠습니까?")
                            .setPositiveButton("네"new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
 
                                    /** * 새로운 인스턴스(onClickListener)를 생성했기 때문에 *
                                     * 버전체크를 다시 해준다. */
                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                        // CALL_PHONE 권한을 Android OS에 요청한다.
                                        requestPermissions(new String[]{Manifest.permission.CAMERA}, 1000);
                                    }
                                }
                            })
                            .setNegativeButton("아니요"new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    Toast.makeText(MainActivity.this"기능을 취소했습니다", Toast.LENGTH_SHORT).show();
                                }
                            }).create().show();
                }
                // 최초로 권한을 요청할 때
                else {
                    // CALL_PHONE 권한을 Android OS에 요청한다.
                    requestPermissions(new String[]{Manifest.permission.CAMERA}, 1000);
                }
            }
            // CALL_PHONE의 권한이 있을 때
            else {
 
            }
        }
        /************권한요청 끝**************/
 
 
    }
 
 
 
/** * 권한 요청에 대한 응답을 이곳에서 가져온다. * *
     *  @param requestCode 요청코드 *
     *  @param permissions 사용자가 요청한 권한들 *
     *  @param grantResults 권한에 대한 응답들(인덱스별로 매칭) */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == 1000) {
            // 요청한 권한을 사용자가 "허용" 했다면...
            if (grantResults.length > 0 && grantResults[0== PackageManager.PERMISSION_GRANTED) {
                // 이곳에 허용했을때 실행할 코드를 넣는다
                // 근데 난 안넣음
 
            } else {
                // 거부했을때 띄워줄 
                Toast.makeText(MainActivity.this"권한요청을 거부했습니다.", Toast.LENGTH_SHORT).show();
            }
        }
    }
 
 
cs



액티비티에서 onCreate 부분에서 권한요청을 날려주면 된다.


메인액티비티에 걸어놨다면 어플을 실행할때 메세지가 뜰 것이다.


최적화를 위해서는


권한이 필요한 액션이 일어날때 권한요청을 물어보는 것이 좋다고 하는데


내가 하는 프로젝트는 웹뷰로 띄워놓고 하는거라


액티비티가 메인액티비티 하나뿐이다.


그리고 귀찮다.



만약 카메라 권한이 아니라 


전화걸기, 데이터접근 등의 권한이라면



Manifest.permission.CAMERA


이부분에서


CAMERA 만 원하는 퍼미션으로 바꿔주면 된다.


물론 하나만 바꾸는게 아니라 저거 적혀있는 모든 코드를 바꿔야 하는건 기본



[안드로이드] 웹뷰 자바스크립트와 안드로이드 자바 연동 방법


안드로이드의 웹뷰를 사용해 개발을 하다 보면 웹뷰에서 띄운 자바스크립트와


안드로이드의 자바 소스간에 연동을 해야 하는 경우가 생긴다



즉 자바스크립트에서 안드로이드 메소드를 호출 하거나


안드로이드에서 자바스크립트 함수를 호출해야 하는 경우인데.


그 방법에 대해서 알아 보도록 하자.



1. mainActivity.java 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final DBHelper dbHelper = new DBHelper(getApplicationContext(), "MoneyBook.db"null1);
        // 웹뷰 셋팅팅
        mWebView = (WebView) findViewById(webView);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.loadUrl(myUrl + "/html/test.html");
        mWebView.setWebChromeClient(new WebChromeClient());
        mWebView.setWebViewClient(new WebViewClientClass());
    
 
        // Bridge 인스턴스 등록
        mWebView.addJavascriptInterface(new AndroidBridge(mWebView, dbHelper, newtwork), "HybridApp");
 
 
 
    }
cs



메인 액티비티의 oncreate 메소드에 웹뷰 셋팅을 해놓고 그 아래에 안드로이드브릿지를 등록 한다.



2. AndroidBridge.java


1번의 15번 라인의 안드로이드 브릿지를 사용하기 위해 클래스를 추가 해 주도록 한다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.xxx.xxxxx;
 
import android.os.Handler;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
 
import java.text.SimpleDateFormat;
import java.util.Date;
 
/**
 * Created by Administrator on 2017-08-03.
 */
 
public class AndroidBridge {
    private final Handler handler = new Handler();
    private WebView mWebView;
    private DBHelper dbHelper;
    private  boolean newtwork;
 
    // 생성자
    // 따로 사용할일 없으면 이거 안만들고 위의 변수도 안만들어도 됨.
    public AndroidBridge(WebView mWebView, DBHelper dbHelper, boolean newtwork) {
        this.mWebView = mWebView;
        this.dbHelper = dbHelper;
        this.newtwork = newtwork;
    }
 
    // DB데이터 가져오기
    @JavascriptInterface
    public void requestData() { // must be final
        handler.post(new Runnable() {
            public void run() {
                Log.d("HybridApp""데이터 요청");
                String test  =  dbHelper.getResult();
                Log.d("HybridApp", test);
                mWebView.loadUrl("javascript:getAndroidData('"+test+"')");
            }
        });
    }
 
    // DB에 데이터 저장하기
    @JavascriptInterface
    public void saveData(final String item, final int num) { // must be final
        handler.post(new Runnable() {
            public void run() {
                Date d = new Date();
 
                String s = d.toString();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
 
                dbHelper.insert(sdf.format(d), item, num);
                Log.d("HybridApp""데이터 저장");
                String test  =  dbHelper.getResult();
                mWebView.loadUrl("javascript:getAndroidData('"+test+"')");
            }
        });
    }
 
 
 
}
cs



DB데이터 가져온다는 내용은 신경쓰지 말자


일단 1번과 2번을 완료 했다면 안드로이드에서 할일은 끝났다.


여기서 봐야 할 것은


30번 43번 라인의 어노테이션이다. API17이상부터 저 어노테이션을 달아주지 않으면


정상 작동하지 않는다.


그리고 31 44번의 requestData, saveData 이 메소드명이 자바스크립트에서 호출하는 이름이 된다.


그리고 37 55번라인은 안드로이드에서 자바스크립트로 데이터를 날려주면서 


자바스크립트 function을 호출하는 부분이다.



3. javascript


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
$(function(){
    window.HybridApp.requestData();
});
 
function saveData(){
    var item = $("#item").val();
    var num = $("#num").val();
    window.HybridApp.saveData(item, num);
}
 
 
function getAndroidData(data){
    alert(data);
 
    var dataArr = data.split("*nn*");
    $("#testDiv").empty();
    for(var count=0; count < dataArr.length; count++){
        $("#testDiv").append("<p>"+dataArr[count]+" </p>");
    }
 
}
cs



자바스크립트에서 안드로이드 메소드를 호출할땐


window.1의 15번라인에서 선언한 이름.2에서 선언한 메소드명();


이런식으로 호출을 해주면 된다.


만약 3번라인의 리퀘스트데이터를 호출하면


2의 31번 메소드가 응답하며 2의 37번 라인이 동작해 자바스크립트 3의 13번function이 동작한다.




물론 위에 보는 것 처럼 안드로이드와 자바스크립트간의 텍스트 데이터도 전송이 가능 하다.



[안드로이드] androidBridge they will not be visible in API 17 오류 해결 방법




none of the methods in the added interface(androidBridge) have been annotated with @android.webkit   they will not be visible in API 17 


이 오류의 해결 방법 입니다.



1. 원인


안드로이드 버전 API 17 이상부터 androidBridge 사용시 메소드에 어노테이션을 사용해야 정상 구동 하도록

바뀌어서 생기는 오류


2. 해결 방법


간단하게 androidBridge에서 사용하는 메소드위에 어노테이션을 추가 하면 됩니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.xxx.xxxx;
 
import android.os.Handler;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import java.text.SimpleDateFormat;
import java.util.Date;
 
/**
 * Created by Administrator on 2017-08-03.
 */
 
public class AndroidBridge {
    private final Handler handler = new Handler();
    private WebView mWebView;
    private DBHelper dbHelper;
    private  boolean newtwork;
 
    // 생성자
    public AndroidBridge(WebView mWebView, DBHelper dbHelper, boolean newtwork) {
        this.mWebView = mWebView;
        this.dbHelper = dbHelper;
        this.newtwork = newtwork;
    }
 
    // 네트워크 상태 확인
    @JavascriptInterface
    public void requestNetwork() { // must be final
        handler.post(new Runnable() {
            public void run() {
                Log.d("HybridApp""네트워크 상태 요청");
                mWebView.loadUrl("javascript:getNetwork("+newtwork+")");
            }
        });
    }
 
 
 
    @JavascriptInterface
    public void setMessage(final String arg) { // must be final
        handler.post(new Runnable() {
            public void run() {
                Log.d("HybridApp""setMessage("+arg+")");
                mWebView.loadUrl("javascript:getAndroidMessage('ANDROID -> JAVASCRIPT CALL!!')");
            }
        });
    }
 
 
}
cs


간단하게 다른거 볼 필요 없이


28번라인에 추가한 어노테이션을 29번같은 메소드 위에 선언하기만 하면 해당 오류가 해결 된다.



[안드로이드] 인터넷 연결상태 확인하는 방법



개발 하는 프로젝트중 인터넷이 연결 되었을땐 서버DB에서 값을 가져오고

연결이 되지 않았을땐 안드로이드의 sqlite에서 값을 가져와야 하는 기능이 있었다


그래서 찾아서 만들었다.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class MainActivity extends AppCompatActivity {
    private WebView mWebView;
    private String myUrl = "file:///android_asset";
    public static final String WIFE_STATE = "WIFE";
    public static final String MOBILE_STATE = "MOBILE";
    public static final String NONE_STATE = "NONE";
    private boolean newtwork = true;
 
 
    @Override
 
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 앱 실행시 체크
        String getNetwork =  getWhatKindOfNetwork(getApplication());
        if(getNetwork.equals("NONE")){
            newtwork = false;
        }
 
    }
 
    // 인터넷 
    public static String getWhatKindOfNetwork(Context context){
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        if (activeNetwork != null) {
            if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
                return WIFE_STATE;
            } else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
                return MOBILE_STATE;
            }
        }
        return NONE_STATE;
    }
}
 
cs




일반적인 메인액티비티에 담았다


원래는 저기에 웹뷰셋팅이나 sqlite관련된 소스들도 있는데 보기 힘드니까 다 지움


중요한건 인터넷이 연결된 상태인지만 체크 하는 것


4~7번은 그냥 편의를 위해 전역변수로 지정해놨는데 사용하지 않아도 된다.


25번의 메소드에서 단순하게 true false만 반환해줘도 되는데


저렇게 쓰면 현재 연결된게 와이파이 인지 모바일네트워크인지 구분이 가능하기 때문에 넣은 것.




[안드로이드] 간단하게 웹뷰 구현


간다하게 안드로이드의 웹뷰를 구현해 보도록 하자



1. 메인 액티비티 소스 (MainActivity.java 소스)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.pois.mtrs_test;
 
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
 
import static com.pois.mtrs_test.R.id.webView;
public class MainActivity extends AppCompatActivity {
    private WebView mWebView;
    private String myUrl = "file:///android_asset"// 접속 URL (내장HTML의 경우 왼쪽과 같이 쓰고 아니면 걍 URL)
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 웹뷰 셋팅팅
        mWebView = (WebView) findViewById(webView);
        mWebView.getSettings().setJavaScriptEnabled(true);
        //mWebView.loadUrl("http://www.pois.co.kr/mobile/login.do");
 
        mWebView.loadUrl(myUrl + "/html/test.html"); // 접속 URL
        mWebView.setWebChromeClient(new WebChromeClient());
        mWebView.setWebViewClient(new WebViewClientClass());
    }
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
            mWebView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
 
    private class WebViewClientClass extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            Log.d("check URL",url);
            view.loadUrl(url);
            return true;
        }
    }
 
 
}
cs




14번 라인의 myurl은 http를 포함한 도메인 주소를 넣으면 된다. 나중에 편하게 쓸일 있을까 해서 걍 변수 처리 한것


23번 라인은 자바스크립트 허용 유무에 대한 것



27번은 웹뷰에 크롬을 사용한다고 하는 건데 저거 안하고 그냥 웹뷰만 쓰면


alert같은 알림창이 뜨지 않는다.


28번 라인에서 셋웹뷰를 한것은


39번부터 시작하는 클래스를 사용하는데


저거 안하면 html 내부에서 다른 페이지로 이동을 할 수가 없다. 그떄그떄 해당 url을 웹뷰에 셋팅해주는 역할을 한다.



2. AndroidManifest.xml 설정 인터넷 퍼미션 추가



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xxx.xxx">
 
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
 
</manifest>
cs



5번 라인의 인터넷 퍼미션을 추가해줘야 해당 앱에서 인터넷에 접속할수 있다.


간단하게 앱에서 인터넷 사용할 권한을 주는 것이다.



3. layout



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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"
    tools:context="com.xxx.xxxx.MainActivity">
 
    <WebView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/webView"
        >
 
 
    </WebView>
 
</LinearLayout>
cs



레이아웃 구조는 이렇게 해주자


웹뷰는 그냥 꽉차게 보여줄거니까 매치 패런트로 해놓는다.



.


[안드로이드] FCM 화면 깨우기 화면 켜지게 하는 방법

2017/07/10 - [Yame Programmer/Android] - [안드로이드] FCM 푸시메세지 웹서버(JAVA)에서 보내기

2017/07/10 - [Yame Programmer/Android] - [안드로이드] FCM 토큰 저장방법 개별 보내는 방법 SharedPreferences 사용

2017/07/12 - [Yame Programmer/Android] - [안드로이드] FCM 백그라운드에서 진동 오도록 하는 방법




후.. FCM메세지를 노티피케이션이 아니라 data로 날리도록 하니


지금까지 삽질해도 안되던 화면 깨우기가 되었다..


진짜 아무것도 모르는 상태로 근본없이 맨땅에 헤딩하니 좀 지친다



화면 깨우기는 간단하다


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void onMessageReceived(RemoteMessage remoteMessage) {
        //추가한것
       // sendNotification(remoteMessage.getData().get("message"));
 
        // 이거 추가 하면 
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE );
        PowerManager.WakeLock wakeLock = pm.newWakeLock( PowerManager.SCREEN_DIM_WAKE_LOCK
                | PowerManager.ACQUIRE_CAUSES_WAKEUP, "TAG" );
        wakeLock.acquire(3000);
 
 
        String title = remoteMessage.getData().get("title");
        String body = remoteMessage.getData().get("body");
        sendNotification(title, body);
    }
cs



이렇게 6,7,8,9,10 번 라인을 추가해주면 된다


그런데 저기에 있는 SCREEN_DIM_WAKE_LOCK는 deprecated 되었다



아 몰랑 그냥 쓸거야!


화면 켜지게 하면 된다구!


지금 안드로이드 버전에서 권장하는 방법은 FLAG_KEEP_SCREEN_ON


이거 쓰라고 하는데


사실 당장 뭐 어떻게 쓰는지도 잘 모르기도 하고


문서들을 찾아보니 뭐 밝게했다가 어둡게도 했다가도 하고 그런 여러가지 기능들이 있는것 같긴 한데


아직 다 써보진 못했다 PARTIAL_WAKE_LOCK 이런거라든가 FLAG_KEEP_SCRREN_ON


이런거 쓰라고 하는데


FLAG_KEEP_SCRREN_ON 얘는 어찌 써야할지 레이아웃에 걸어줘야 하는 애 같아서 못썻고


PARTIAL_WAKE_LOCK 이건 화면이 안켜진다. 그래서 저 위의 코드를 사용하기로 함.


물론 소스는 더 많이 있고 써보기도 했는데 백그라운드에서 안돌아갔던 문제 때문에


되는건지 모르겠고 다시 그 소스들 찾아가면서 해보긴 귀찮다.


그건 다음에 또 이런 어플 만들때 되면 해보도록 하자


아니면 해본 사람들이 댓글을 남겨준다면 더 고마울 것이다.






[안드로이드] FCM 백그라운드에서 진동 오도록 하는 방법






얼마전 포스팅에서 웹서버를 통해  FCM 메세지를 날리는 방법에 대해서 알아보았다


2017/07/10 - [Yame Programmer/Android] - [안드로이드] FCM 토큰 저장방법 개별 보내는 방법 SharedPreferences 사용

2017/07/10 - [Yame Programmer/Android] - [안드로이드] FCM 푸시메세지 웹서버(JAVA)에서 보내기



그런데 문제가 있었다.


어플을 켜놓은 상태에선 진동이 오는데


어플을 끄거나 화면을 끈 상태에선 진동알람도 안오고 화면이 켜지는 것도 안되서


알람이 온줄 모르는 상태가 되버린 것



이것때문에 얼마나 삽질을 했던가..



화면켜지는건 고사하고 아얘 어플 끈 상태에선


상단에 알람바만 조용히 생기고 애초에 onMessageReceived 여기서 지정해 놓은 것들이


아얘 안돌아 가는 것 같았다


삽질을 하다가


결국 스택오버 형님들의 글에서 답을 찾았다


저번 포스팅을 보면  웹서버에서 FCM요청을 할떄



1
2
3
4
5
6
7
8
JSONObject root = new JSONObject();
                JSONObject notification = new JSONObject();
                notification.put("body""공조기 장애 현재상태 : OFF");
                notification.put("title""알림 입니다.");
                notification.put("icon""ic_message");
                root.put("notification", notification);
                root.put("to", token);
                root.put("click_action""OPEN_ACTIVITY");
cs




이런식으로 보냈었는데 6번라인의저 노티피케이션이 문제였다.


노티피케이션으로 날려주면 onMessageReceived가 실행이 안된단다


그래서 저 노티피케이션을 data로 바꾸어 주었다



1
2
3
4
5
6
7
8
                JSONObject root = new JSONObject();
                JSONObject notification = new JSONObject();
                notification.put("body""공조기 장애 현재상태 : OFF");
                notification.put("title""알림 입니다.");
                notification.put("icon""ic_message");
                root.put("data", notification);
                root.put("to", token);
                root.put("click_action""OPEN_ACTIVITY"); // click_action 추가!
cs



이렇게 바꾸고 나니 백그라운드 상태에서도 설정해놓은 vibrate대로 진동도 잘온다!!


화면켜지는것까진 바라지도 않는다 


일단 사용자한테 알람이 왔다고 알리기만 하면 되니까



그렇다면 안드로이드 에서도


받는 부분의 메세지를 다르게 받을 필요가 있었다



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public void onMessageReceived(RemoteMessage remoteMessage) {
        //추가한것
       // sendNotification(remoteMessage.getData().get("message"));
        
        // 이렇게 데이터에 있는걸 키값으로 뽑아 쓰면 된다.
        String title = remoteMessage.getData().get("title");
        String body = remoteMessage.getData().get("body");
        sendNotification(title, body);
    }
 
    private void sendNotification(String title, String body) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 
        PendingIntent pendingIntent = PendingIntent.getActivity(this0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);
 
        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle(title)
                .setContentText(body)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setVibrate(new long[]{10001000})
                .setLights(Color.BLUE,1,1)
                .setContentIntent(pendingIntent);
        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
 
    }
cs



이렇게 코드를 바꿔주면 된다


기존 코드에서 6,7번 라인과 11번읜 매개변수만 바꿔주면 끝!



후.. 이제 다시 화면도 켜지게 하는 방법을 찾아 떠나보도록 하자....

-------------------------------------------------------------------------------

방법 찾았음 ㅋ


2017/07/12 - [Yame Programmer/Android] - [안드로이드] FCM 화면 깨우기 화면 켜지게 하는 방법




 

[안드로이드] FCM 토큰 저장방법 개별 보내는 방법 SharedPreferences 사용 


이전 포스팅은 걍 설치한 사람들한테 죄다 다 보내는 방법이었다.


2017/07/10 - [Yame Programmer/Android] - [안드로이드] FCM 푸시메세지 웹서버에서 보내기




그런데 우린 특정인들에게만 보내고 싶을때가 있다



그런데 망할 네이티브와 웹뷰간의 세션공유도 어렵고 쿠키가져오는것도 뭔말인지도 모르겠고


3일을 삽질하다가 그냥 방법을 바꿔버리기로 했다



웹뷰에 있는 js를 안드로이드 네이티브에서 호출을 할 수 있다는걸 알았기에



안드로이드에서 토큰값을 JS로 날려주고 JS에선 사용자ID값과 토큰을 같이 서버로 날려 저장하는


방식을 사용하기로 한다.



우선 안드로이드에서 JS를 호출 하는 방법인다. 물론 변수도 같이 날려줄 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
 
        // 웹뷰 셋팅팅
       mWebView = (WebView)findViewById(webView);
 
        // 자바스크립트 사용을 반드시 true로 해야 한다
        mWebView.getSettings().setJavaScriptEnabled(true);
 
        mWebView.loadUrl(myUrl+"/mobile/login");
        mWebView.setWebChromeClient(new WebChromeClient());
        mWebView.setWebViewClient(new WebViewClientClass());
 
        mWebView.addJavascriptInterface(new AndroidBridge(), "android");
        //추가한 라인
        FirebaseMessaging.getInstance().subscribeToTopic("ALL");
        Log.d("아오","테스트");
 
    }
cs



10번 라인을 꼭 추가해준 후



1
mWebView.loadUrl("javascript:setMessage('"+token+"')");
cs


URL요청하는 부분에다가 저거 한줄 넣으면


해당 페이지의  setMessage 라는 펑션이 작동 한다!!!! 물론 저 안에 토큰이라는 변수값도 함께!!!



당연히 js에는



1
2
3
4
5
6
7
8
9
10
11
12
13
function setMessage(arg) {
    // alert(arg);
    var param = {};
    param.token = arg;
    gPost("/저장하러 날릴 URL"
            ,param
            , function(response){
                if(!response.result){
                    alert("디바이스 정보 저장 오류 어플리케이션을 다시 시작해 주십시오");
                }
            });
     
cs



이런식으로 같은 이름의 펑션을 만들어 주어야 한다.





이렇게 하면 토큰과 사용자 ID를 묶어서 저장할 수가 있다.




여기서 문제는 저 토큰값을 어떻게 가지고 오느냐이다.



토큰값은 어플 설치될때 한번 생성되는데 그걸 어디다 저장할까?


토큰 한줄 저장하자고 로컬DB사용하는건 좀 오버하는거 같다


그래서 찾아낸것이


SharedPreferences  바로 이것!@!!!!!!



우왕... 개짱.. 짱짱맨.. 그냥 데이터 파일로 저장하는거임



다시 안드로이드의 토큰생성하는 곳을 가보자



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 private void sendRegistrationToServer(String token) {
        // Add custom implementation, as needed.
 
        // 만들어진 토큰을 저장한다!!!
        SharedPreferences pref = getSharedPreferences("pref", MODE_PRIVATE);
        SharedPreferences.Editor editor = pref.edit();
        editor.putString("token", token);
        editor.commit();
        // 여기까지!!!
 
        OkHttpClient client = new OkHttpClient();
        RequestBody body = new FormBody.Builder()
                .add("Token", token)
                .build();
 
        //request
        Request request = new Request.Builder()
                .url("이제 이건 노신경")
                .post(body)
                .build();
 
        try {
            client.newCall(request).execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
 
    }
cs



5~8번 라인을 추가해주도록 하자 


그럼 불러올땐


1
2
3
4
   // 저장해놨던 토큰값 가져와서 전달
   SharedPreferences pref = getSharedPreferences("pref", MODE_PRIVATE);
   String token =  pref.getString("token""");
   mWebView.loadUrl("javascript:setMessage('"+token+"')");
cs



이렇게 토큰이라는 이름으로 불러오면 된다!!!


그러면 끝!!!


이제 사용자 아이디와토큰을 묶어서 디비에 저장해놓고


보내고 싶은사람한테 골라서 보내면 된다!!



+ Recent posts