강제 업데이트..

또 찾아온 강제 업데이트..

 

앱 스토어에 업데이트 하기 위해 target API Level을 34이상으로 조정

 

build.gradle(Module:app)에서 compileSdkVersion, targetSdkVersion을 기존 33에서 34로 변경 후 빌드

 

오류 발생.. 

Execution failed for task ':app:processDebugResources'.
> A failure occurred while executing com.android.build.gradle.internal.res.LinkApplicationAndroidResourcesTask$TaskAction
   > AAPT2 aapt2-4.2.2-7147631-osx Daemon #0: Unexpected error during link, attempting to stop daemon.
     This should not happen under normal circumstances, please file an issue if it does.

 

검색 , gpt 등에서 확인해보니 gradle 버전을 최선으로 변경하고, 여러 설정 변경 후 "File > Invalidate Caches / Restart." 하라는데 모두 실패

 

성공한 my case 올려봄. (IDE: Android Studio Koala | 2024.1.1)

 

1. Settings > Build,Execution,Deployment > Build Tools > Gradle 메뉴

- Gradle user home 에 gradle 7.6.4 버전 설정해줌.(로컬 특정 위치에 저장해야함 )

- Gradle JDK 에 Java 11 경로 설정해줌.

gradle 버전 다운로드 : https://gradle.org/releases/

 

Gradle | Releases

Find binaries and reference documentation for current and past versions of Gradle.

gradle.org

 

 

2.gradle-wrapper.properties 에 distributionUrl 에 gradle 7.5 설정

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

 

3. Tools > AGP(Android Gradle Plugin) Upgrade Assistant.. 를 통해 업데이트

- build.gradle(project)에서 gradle 관련 classpath 잡아주면 업데이트가 되는지 알았으나, 완벽하게 되지 않는 모양이다.

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:7.4.2'
        
        ...

 

Run selected steps 를 클릭하여 실행

 

정상적으로 빌드 성공..

 

build tool에 대한 이해 부족으로 매번 삽질하네.. 공부 좀 해야겠다!

https://developers.google.com/oauthplayground/

 

STEP1. Select & authorize APIs

> 1. Firebase Cloud Messaging API v1  - https://www.googleapis.com/auth/cloud-platform

       선택

   2. 하단 'Authorize APIs' 버튼 클릭 후 계정 선택 

      (단 , firebase console에 해당 프로젝트 등록한 계정을 선택해야함)

 

STEP2. Exchange authorization code fo tokens

> 1. "Exchange authorization code for tokens" 버튼 눌러 접속 계정으로 인증 

   2. Auto-refresh the token before it expires 체크

STEP3. Configure request to API

 

1. 발송 테스트일 경우

 

HTTP Method : POST 설정, 

Request URI : https://fcm.googleapis.com/v1/projects/{프로젝트 이름}/messages:send

입력

2. Enter request body 클릭 하여 아래 내용 입력

{
   "message":{
      "token":"coIUgZJYdESHigmL4qWahT:APA91bHI5Z1FoK6ZjtnN9aipO.....",
      "notification":{
        "body":"This is an FCM notification message!",
        "title":"FCM Message"
      }
   }
}

 

3. Send the request 버튼 클릭하여 실제 기기에서 푸시 알림 수신되는지 확인

 

 

더보기

cordova 버전 : 9.0.0

gradle 버전 : 6.7.1

exit app 플러그인 추가 할 때 아래처럼 에러 발생

 

goomgoom@starnet example_copy % cordova plugin add cordova-plugin-app-exit
Installing "cordova-plugin-app-exit" for android
Failed to install 'cordova-plugin-app-exit': Error: /Users/goomgoom/AndroidStudioProjects/example_copy/platforms/android/cordova/version: Command failed with exit code 1 Error output:
node:internal/modules/cjs/loader:1215
  throw err;
  ^

Error: Cannot find module 'properties-parser'
Require stack:
- /Users/goomgoom/AndroidStudioProjects/example_copy/platforms/android/cordova/lib/AndroidProject.js
- /Users/goomgoom/AndroidStudioProjects/example_copy/platforms/android/cordova/Api.js
- /Users/goomgoom/AndroidStudioProjects/example_copy/platforms/android/cordova/version
    at Module._resolveFilename (node:internal/modules/cjs/loader:1212:15)
    at Module._load (node:internal/modules/cjs/loader:1038:27)
    at wrapModuleLoad (node:internal/modules/cjs/loader:212:19)
    at Module.require (node:internal/modules/cjs/loader:1297:12)
    at require (node:internal/modules/helpers:123:16)
    at Object.<anonymous> (/Users/goomgoom/AndroidStudioProjects/example_copy/platforms/android/cordova/lib/AndroidProject.js:22:25)
    at Module._compile (node:internal/modules/cjs/loader:1460:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1544:10)
    at Module.load (node:internal/modules/cjs/loader:1275:32)
    at Module._load (node:internal/modules/cjs/loader:1091:12) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/Users/goomgoom/AndroidStudioProjects/example_copy/platforms/android/cordova/lib/AndroidProject.js',
    '/Users/goomgoom/AndroidStudioProjects/example_copy/platforms/android/cordova/Api.js',
    '/Users/goomgoom/AndroidStudioProjects/example_copy/platforms/android/cordova/version'
  ]
}

Node.js v22.3.0
    at ChildProcess.whenDone (/usr/local/lib/node_modules/cordova/node_modules/cordova-common/src/superspawn.js:135:23)
    at ChildProcess.emit (node:events:520:28)
    at maybeClose (node:internal/child_process:1105:16)
    at Socket.<anonymous> (node:internal/child_process:457:11)
    at Socket.emit (node:events:520:28)
    at Pipe.<anonymous> (node:net:339:12)

 

해결:  npm install properties-parser 

(properties-parser  수동으로 추가)

 

 

goomgoom@starnet android % cordova plugin add cordova-plugin-app-exit
Installing "cordova-plugin-app-exit" for android
(node:14085) [DEP0128] DeprecationWarning: Invalid 'main' field in '/Users/goomgoom/AndroidStudioProjects/example_copy/node_modules/objectorarray/package.json' of 'dist/index.js'. Please either fix that or report it to the module author
(Use `node --trace-deprecation ...` to show where the warning was created)
Adding cordova-plugin-app-exit to package.json
goomgoom@starnet android % cordova plugin ls                         
cordova-plugin-app-exit 0.0.1 "ExitApp"
cordova-plugin-whitelist 1.3.4 "Whitelist"

 

잘 설치 됨

google play console 들어가 보니 난리났다..

android 버전이 12이상인 기기에서 백그라운드 알림 이벤트 수신시 아래와 같이 에러가 났다.

Exception java.lang.IllegalArgumentException: com.bizentro.uniportal: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.
  at android.app.PendingIntent.checkFlags (PendingIntent.java:382)
  at android.app.PendingIntent.getActivityAsUser (PendingIntent.java:465)
  at android.app.PendingIntent.getActivity (PendingIntent.java:451)
  at android.app.PendingIntent.getActivity (PendingIntent.java:415)
  at com.google.firebase.messaging.CommonNotificationBuilder.createContentIntent (com.google.firebase:firebase-messaging@@21.0.1:5)
  at com.google.firebase.messaging.CommonNotificationBuilder.createNotificationInfo (com.google.firebase:firebase-messaging@@21.0.1:20)
  at com.google.firebase.messaging.CommonNotificationBuilder.createNotificationInfo (com.google.firebase:firebase-messaging@@21.0.1:6)
  at com.google.firebase.messaging.DisplayNotification.handleNotification (com.google.firebase:firebase-messaging@@21.0.1:4)
  at com.google.firebase.messaging.FirebaseMessagingService.dispatchMessage (com.google.firebase:firebase-messaging@@21.0.1:8)
  at com.google.firebase.messaging.FirebaseMessagingService.passMessageIntentToSdk (com.google.firebase:firebase-messaging@@21.0.1:8)
  at com.google.firebase.messaging.FirebaseMessagingService.handleMessageIntent (com.google.firebase:firebase-messaging@@21.0.1:3)
  at com.google.firebase.messaging.FirebaseMessagingService.handleIntent (com.google.firebase:firebase-messaging@@21.0.1:3)
  at com.google.firebase.messaging.EnhancedIntentService.lambda$processIntent$0$EnhancedIntentService
  at com.google.firebase.messaging.EnhancedIntentService$$Lambda$0.run
  at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1167)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:641)
  at com.google.android.gms.common.util.concurrent.zza.run
  at java.lang.Thread.run (Thread.java:920)

PendingIntent.getActivity()에 분명  PendingIntent.FLAG_IMMUTABLE 추가했는데..

public class MyFirebaseMessagingService extends FirebaseMessagingService {

...

   /**
     * 서버로부터 수신받은 메시지를 보여준다.
     * @param remoteMessage
     */
    private void sendNotification(Context context, RemoteMessage remoteMessage) {
        ...
		
        PendingIntent contentIntent = PendingIntent.getActivity(this, notiId, mainWeb , PendingIntent.FLAG_IMMUTABLE);

    }    
 
 }

 

구글링 후 아래와 같이 해결했음.

 

build.gradle (Module)의 dependencies { }  부분에서 아래 부분 수정함

dependencies {
    ...
    //최신버전으로 수정 (기존 1.0.0)
    implementation 'androidx.appcompat:appcompat:1.5.1'

    
	//최신 버전으로 변경(기존 16, 17버전대)
    implementation 'com.google.firebase:firebase-core:21.1.1'
    implementation 'com.google.firebase:firebase-iid:21.1.0'
    implementation 'com.google.firebase:firebase-messaging:23.1.1'
    
    //추가
    implementation 'androidx.work:work-runtime:2.7.1'
    
    ...
}

 

오랜만에 앱 업데이트..

또 강제 업그레이드?!

build.grale 수정하고 나니

compileSdkVersion, targetSdkVersion -> 31
역시나..

> Task :app:processDebugMainManifest FAILED

[androidx.vectordrawable:vectordrawable-animated:1.0.0] /Users/wonhochoe/Downloads/gradle-4.8.1/caches/transforms-2/files-2.1/17c854dfb65cc4cb6b6a29797e63f450/vectordrawable-animated-1.0.0/AndroidManifest.xml Warning:
Package name 'androidx.vectordrawable' used in: androidx.vectordrawable:vectordrawable-animated:1.0.0, androidx.vectordrawable:vectordrawable:1.0.0.

/Users/wonhochoe/AndroidStudioProjects/android-220803/app/src/main/AndroidManifest.xml Error:
Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined.
See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.

/Users/wonhochoe/AndroidStudioProjects/android-220803/app/src/main/AndroidManifest.xml Error:
Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined.
See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.



See http://g.co/androidstudio/manifest-merger for more information about the manifest merger.

그대로 해석하면, Android 12 이상 타겟팅하고 있는 컴포넌트(Activity, service 등등) 중 인텐트 필터 포함하고 있는 애들은

 

명시적으로 android:exported 값을 넣어줘야함.

        <activity
            android:name=".MainActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:theme="@style/AppTheme"
            android:exported="true"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

 

android:exported
이 요소는 다른 애플리케이션의 구성요소에서 활동을 시작할 수 있는지를 설정합니다.
"true"인 경우 모든 앱에서 활동에 액세스할 수 있으며 정확한 클래스 이름으로 활동을 시작할 수 있습니다.
'false'인 경우 활동은 같은 애플리케이션의 구성요소나 사용자 ID가 같은 애플리케이션, 권한이 있는 시스템 구성요소에서만 시작될 수 있습니다. 이는 인텐트 필터가 없는 경우의 기본값입니다.
앱의 활동에 인텐트 필터가 포함되면 다른 앱에서 활동을 시작할 수 있도록 이 요소를 "true"로 설정합니다. 예를 들어 활동이 앱의 기본 활동이고 category 'android.intent.category.LAUNCHER'를 포함한 경우입니다.

이 요소가 'false'로 설정되어 있고 앱에서 활동을 시작하려고 하면 시스템에서 ActivityNotFoundException이 발생합니다.

'android.intent.category.LAUNCHER' 인텐트 필터 갖고 있는 Activity에 android: exported = false 값을 지정하면 앱이 실행 안됨

 

 

며칠 삽질의 기억을.. 잊지 않기 위해 남긴다. 미래의 나에게 알리기 위해..

 

수정:

인증서 인증기관(CA)의 인증서를 google에서 다운로드 받는 부분 정정

 

문제의 발단..

 

배포 중인 앱을 사용하는 고객사 중 https를 사용하는 고객사들이 늘어나고 있다.

SSL 관련 에러 runtime 에러 중 handshake 관련 에러, CertPathValidation 관련 에러.. 

구글링해보면 가장 많이 나오는 내용이다. 하나같이 보안이 취약해짐을 경고한다.

/**
     * Trust every server - don't check for any certificate
     */
    private void trustAllHosts() {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[] {};
            }

            @Override
            public void checkClientTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }
        }};

        // Install the all-trusting trust manager
        try {
            SSLContext sc = SSLContext.getInstance("SSL");//TLS
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String s, SSLSession sslSession) {
                    return true;
                }
            });
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

그런데, 웹페이지에서 첨부 파일을 다운로드 하려고 하면, 에러 없이 해당 코드 다 지나가는데 정작 다운로드가 안된다.

 

2022-02-18 09:36:43.932 5444-18175/? E/CONSCRYPT: ------------------Untrusted chain: ----------------------
2022-02-18 09:36:43.932 5444-18175/? E/CONSCRYPT: == Chain0 == 
     Version:   3
2022-02-18 09:36:43.932 5444-18175/? E/CONSCRYPT:  AuthorityKeyIdentifier:   41830168014f5cdd53c0850f96a4f3ab797da5683e669d268f7
2022-02-18 09:36:43.934 5444-18175/? E/CONSCRYPT:  SubjectKeyIdentifier:   41604144ddfc81a25282145b8a8d443e77730654eaf2141
2022-02-18 09:36:43.934 5444-18175/? E/CONSCRYPT:  Serial Number:   57a4fb9c8db5886950fea7c6
2022-02-18 09:36:43.934 5444-18175/? E/CONSCRYPT:  SubjectDN:   CN=work.synopex.com
2022-02-18 09:36:43.935 5444-18175/? E/CONSCRYPT:  IssuerDN:   CN=AlphaSSL CA - SHA256 - G2, O=GlobalSign nv-sa, C=BE
2022-02-18 09:36:43.935 5444-18175/? E/CONSCRYPT:  Get not before:   Tue Dec 07 13:34:04 GMT+09:00 2021
2022-02-18 09:36:43.936 5444-18175/? E/CONSCRYPT:  Get not after:   Sun Jan 08 13:34:04 GMT+09:00 2023
2022-02-18 09:36:43.936 5444-18175/? E/CONSCRYPT:  Sig ALG name:   SHA256withRSA
2022-02-18 09:36:43.936 5444-18175/? E/CONSCRYPT:  Signature:   3f5733ba696f079777d75c5689643ea51dd77397a52783e0929ce8e059c8a54368a05fbebc4930ad2348eaf390165aaacfaa430240643cd1581faf58335f20deff423905fe9b5caa1b9e80cafbdfe738079d8db973b3d993019fece0106f2b58bac3dfd72870d2a669d27f5a93e3ff53ff609b287a7135e5c2afbc35cec764af022479eee2c4e6703fded4cd1464d1fc6497bb9717ea37fd1ab66e970588df32c30f13e4d790a3fa90be2f3b997694bcea3868575d065f58c4606beb5d66cf3c21cb03d1126aeeefd63523b38b5c5949be2a04adbcf263d7822cf7519641c9b0b61ccf032363a1e351a12af8d71c35dc42f440902066bc9662af5c93bc491df7
2022-02-18 09:36:43.981 5444-18175/? E/CONSCRYPT:  Public key:
     
     30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03
     82 01 0f 00 30 82 01 0a 02 82 01 01 00 bb 53 2d 60 f9 db ce
     17 45 aa 55 20 b9 92 ed 67 aa 31 1a 74 14 16 14 5f a3 43 fb
     f5 72 0f f9 fc 2d d7 75 51 04 58 a5 9d d7 23 6c 60 fa 43 40
     53 45 a8 00 61 e4 80 5c 08 a7 42 d7 74 bc 1e af ee cd 2b aa
     ce 3d 73 4a c1 78 c7 d9 f1 9f fd 13 e8 18 6f f5 33 f6 23 48
     46 cd 0c eb 14 c5 99 7d ff a3 93 9e 02 bc ea 72 41 c0 d1 58
     b5 e9 e3 3e 79 79 b1 9f 25 ed 3b e0 85 49 a0 bd 45 04 6d fc
     86 fc 6e e9 0a bc be e1 23 f0 8f 8d 64 1d 3d 72 9b a7 01 c8
     b0 1e b6 60 ef 8a 08 6f a7 52 e3 9e 0e 3a de 73 56 30 03 a1
     62 93 78 59 6d 6f cd 07 e0 a3 a8 00 90 94 cb b6 1e 9b a3 8e
     c3 d9 a5 88 38 0b a0 6d 63 6e 7e c0 8a 3c 8e 17 39 ce ea 17
     29 65 c8 25 01 bd 67 01 88 f2 d1 c7 63 b4 db 67 32 a3 9e 5f
     0a ab fa 4f a2 3a 95 37 1d 18 b2 38 b4 df 9f b7 e5 8d 01 00
     ec 9d 37 af 08 18 76 27 77 02 03 01 00 01
2022-02-18 09:36:43.990 5444-18175/? W/DownloadManager: [402] Stop requested with status HTTP_DATA_ERROR: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
2022-02-18 09:36:44.041 4159-4159/? W/NotificationEntryMgr: removeNotification for unknown key: 0|com.android.providers.downloads|0|1:com.goom.goom|10050
2022-02-18 09:36:47.264 3312-3615/? E/BufferQueueProducer: [Toast[16744]#0] disconnect: not connected (req=1)
2022-02-18 09:36:47.265 16744-17078/com.goom. W/libEGL: EGLNativeWindowType 0x7f08928010 disconnect failed

Trust anchor for certification path not found..

Trust anchor?
https://ko.theastrologypage.com/trust-anchor

'뭐지? 앱이 문젠가? 서버 문젠가?

처음엔 서버 쪽을 의심했다.

에러도 없고 , 무엇보다 같은 앱에서 정상동작 하는, https 사용 고객사가 있었기 때문.. (안되려면 다 안되야지.. 그게 더 수상해..)

nginx 문제 인가 해서 , 바로 tomcat으로 연결해보고.. setHeader("Pragma","no-cache") 도 해보고..

그냥 구글링해서 조금이라도 관련된 내용이면 이것도 해보고 다 해보면서 멘붕 중에..

 

Logcat 에서 No Filter로 보니...

 

2022-02-17 16:56:18.289 6795-5125/? E/CONSCRYPT:  Public key:
     
     30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03
     82 01 0f 00 30 82 01 0a 02 82 01 01 00 bb 53 2d 60 f9 db ce
     17 45 aa 55 20 b9 92 ed 67 aa 31 1a 74 14 16 14 5f a3 43 fb
     f5 72 0f f9 fc 2d d7 75 51 04 58 a5 9d d7 23 6c 60 fa 43 40
     53 45 a8 00 61 e4 80 5c 08 a7 42 d7 74 bc 1e af ee cd 2b aa
     ce 3d 73 4a c1 78 c7 d9 f1 9f fd 13 e8 18 6f f5 33 f6 23 48
     46 cd 0c eb 14 c5 99 7d ff a3 93 9e 02 bc ea 72 41 c0 d1 58
     b5 e9 e3 3e 79 79 b1 9f 25 ed 3b e0 85 49 a0 bd 45 04 6d fc
     86 fc 6e e9 0a bc be e1 23 f0 8f 8d 64 1d 3d 72 9b a7 01 c8
     b0 1e b6 60 ef 8a 08 6f a7 52 e3 9e 0e 3a de 73 56 30 03 a1
     62 93 78 59 6d 6f cd 07 e0 a3 a8 00 90 94 cb b6 1e 9b a3 8e
     c3 d9 a5 88 38 0b a0 6d 63 6e 7e c0 8a 3c 8e 17 39 ce ea 17
     29 65 c8 25 01 bd 67 01 88 f2 d1 c7 63 b4 db 67 32 a3 9e 5f
     0a ab fa 4f a2 3a 95 37 1d 18 b2 38 b4 df 9f b7 e5 8d 01 00
     ec 9d 37 af 08 18 76 27 77 02 03 01 00 01
2022-02-17 16:56:18.295 6795-5125/? W/DownloadManager: [393] Stop requested with status HTTP_DATA_ERROR: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
2022-02-17 16:56:18.296 3837-3848/? D/ConnectivityService: filterNetworkStateForUid() uid: 10362, pid: 6795

DownloadManager 가 Stop 됐다고? 또 그 놈의 Trust anchor 때문에?

 

답답한 마음에 Android Developer 사이트를 둘러보던 중..

예전에도 많이 , 자주 봤던.. HTTPS 관련 페이지를 천천히 정독하기 시작..

 

https://developer.android.com/training/articles/security-ssl

 

HTTPS 및 SSL을 사용한 보안  |  Android 개발자  |  Android Developers

HTTPS 및 SSL을 사용한 보안 현재 기술적으로 전송 계층 보안(TLS)이라고 알려진 보안 소켓 레이어(SSL)는 클라이언트와 서버 간의 암호화된 통신을 위한 공통 기본 토대입니다. 애플리케이션이 SSL을

developer.android.com

https://developer.android.com/training/articles/security-config

 

네트워크 보안 구성  |  Android 개발자  |  Android Developers

앱 개발자가 안전한 구성 파일에서 네트워크 보안 설정을 사용자설정할 수 있는 기능입니다.

developer.android.com

 

그러다 눈에 들어온 부분..

인증서파일을 한번 추가해볼까?

 

 

한번 인증서  추가해보자

인증서 전달 받을 때, 보통 .key 및 (인증서).crt, (체인).crt, (루트).crt 받기도 하고, .key 제외한 인증서만 받는 경우도 있는데

 

여기서 사용할 파일은 (인증서).crt 

 

일단, AndroidManifest.xml 파일에서 아래 부분 추가 안되어 있으면 추가!

    <?xml version="1.0" encoding="utf-8"?>
    <manifest ... >
        <application android:networkSecurityConfig="@xml/network_security_config" //추가
                        ... > 
            ...
        </application>
    </manifest>

 

res>xml>network_security_config.xml 수정

 

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">(도메인 정보 ex)naver.com</domain>
        <trust-anchors>
            <certificates src="@raw/sectigo_org_ca"/>
        </trust-anchors>
    </domain-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">(도메인 정보 ex)google.com</domain>
        <trust-anchors>
            <certificates src="@raw/(인증서 파일 이름)"/>
        </trust-anchors>
    </domain-config>
</network-security-config>

참고로, cleartextTrafficPermitted 옵션은 간단하게 말해 HTTP 연결을 허용할지 여부이다.

 

자세한 내용은 아래 링크 참고

https://developer.android.com/reference/android/security/NetworkSecurityPolicy?hl=ko#isCleartextTrafficPermitted()

 

NetworkSecurityPolicy  |  Android Developers

 

developer.android.com

public HttpsURLConnection postHttps(Context context,String url){
        HttpsURLConnection urlConnection = null;
        try{
            // Load CAs from an InputStream
            // (could be from a resource or ByteArrayInputStream or ...)
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            // From https://www.washington.edu/itconnect/security/ca/load-der.crt

            //인증서 경로 저장
             InputStream  is = context.getResources().openRawResource(R.raw.sectigo_org_ca);
            
            InputStream caInput = new BufferedInputStream(is);
            Certificate ca;
            try {
                ca = cf.generateCertificate(caInput);
            } finally {
                caInput.close();
            }

            // Create a KeyStore containing our trusted CAs
            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);

            // Create a TrustManager that trusts the CAs in our KeyStore
            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);

            // Create an SSLContext that uses our TrustManager
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), null);

            // Tell the URLConnection to use a SocketFactory from our SSLContext
            URL toUrl = new URL(url);
            urlConnection =
                    (HttpsURLConnection)toUrl.openConnection();
            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
            urlConnection.setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
                    return hv.verify("server_domain",session);
                }
            });
            //urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
            //InputStream in = urlConnection.getInputStream();
            /*InputStream in = urlConnection.getInputStream();
            IOUtils.copy(in, System.out);*/

        }catch (Exception e){
            e.printStackTrace();
        }
        return urlConnection;
    }

와! 이제 그 Trust anchor 도 안뜨고.. 첨부파일 다운로드도 정상적으로 되고..

 

역시.. 귀찮다고 시도도 안해보고 일찌감치 포기하면.. 더 많은 시간, 체력을 뺏긴다는걸 이번 경험으로 또 알게됨.

 

 

그 외 참고 사이트

SSL문제 해결기:
https://modelmaker.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-SSL-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0%EA%B8%B0
인증서 정보 찾기 : https://info-lab.tistory.com/265

 

 

더 확인할 문제
특정 인증기관의 인증서(ex. setigo) 는 인증서 파일을 등록하지 않아도 접속 및 실행에 문제 없는데, 어떤 CA의 인증서는 꼭
등록해야만 앱이 실행되는 이유..

 

 

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

(삭제)

더보기

먼저, 추가하고자 하는 사이트의 인증서 정보를 알아보자.

openssl s_client -connect (사이트 도메인):443 | openssl x509 -noout -subject -issuer
-- ex)openssl s_client -connect google.com:443 | openssl x509 -noout -subject -issuer

 

 

CA(인증기관) 정보 Get

어디서 다운 받지? 그대로 구글에 치면 됨 이렇게..

AlphaSSL CA - SHA256 - G2 Download
Download Certificated(Binary/DER) 버튼 클릭

다른 인증서 다운로드 사이트도 유사하다 파일 다운로드/ Base64 보기..

 

거의 다왔다.. (정리하면서 보니.. 얼마 안되네..)

 

왜인지 몰라도.. android에 .cer 형식으로 하면 인식이 안되서.. .crt 형식으로 변환 

openssl x509 -inform PEM -in (.cer파일 경로) -out (.crt 파일 경로)

ex) openssl x509 -inform PEM -in gsalphasha2g2r1.cer -out gsalphasha2g2r1.crt

이제 res>raw> 경로에 넣어주기

 

androidManifes.xml 파일에 추가

+ Recent posts