회사에서 개발중인 C 프로젝트를 플레이스토어에 내부테스트 버전으로 올렸는데,
"앱 업데이트를 출시하려면 2024년 8월 31일까지 대상 API 수준을 업데이트하세요."
라는 메세지가 있었다.

보기엔 별 일 아니었다. 간단하게 ProjectSettings에서 target API를 33->34로 바꿔주면 될 줄 알았다.

그렇게 빌드를 했을 때에 아래같은 에러가 뜨며 빌드가 중단됐다.

WARNING:We recommend using a newer Android Gradle plugin to use compileSdk = 34

This Android Gradle plugin (7.4.2) was tested up to compileSdk = 33

This warning can be suppressed by adding
    android.suppressUnsupportedCompileSdk=34
to this project's gradle.properties

The build will continue, but you are strongly encouraged to update your project to
use a newer Android Gradle Plugin that has been tested with compileSdk = 34

지금 사용중인 Android gradle plugin 버전은 targetAPI를 33까지만 지원한다는 내용이었다.


해결 과정

구구절절 보기

C 프로젝트 에서 사용중인 유니티 버전은 최신 lts버전인 2022.3.39f1였다.
해당 버전에서는 Android gradle plugin 7.4.2를 사용중이고, 이것은 API레벨34에 적합하지 않다는 로그가 나오고 있다.

너무 모순이었다. 한마디로
최신버전이 API34레벨을 지원하지 않는데, 구글에서는 API레벨34를 원한다는거였다.

/

분명 나랑 같은 처지의 개발자가 많을텐데, 구글링 했을때 그런 사람이 너무 적었다.
뭔가 이상하다는걸 눈치 챘어야했는데.. 한발 빼서 멀리서 보지 않고 또 머리 들이밀면서 깊숙히 파고들었다.

정말 많은 포럼과 문서를 읽었고 직접 파일을 타이핑해서 수정해보고, 여러가지 새 버전의 gradle 파일도 받아서 바꿔치기 해보고, 환경변수도 건드리는 등등 참 많이 해봤다. 회사 cto님이랑 구글밋까지 하면서 찾아보았다.

/

빌드는 계속 실패했고, 머리를 식히고 생각해보니 바로 어제 구글에 업데이트했던 N 프로젝트가 생각났다.
생각해보니 N 프로젝트에도 분명 API 34로 올리라는 메세지가 왔어서, 별 문제없이 내가 올렸었다. 근데 왜 C프로젝트만 이렇게 복잡할까?

당장 N 을켜서 C 와 뭐가 다른지 비교했다.

  1. N의 gradle 버전을 봤는데 C와 같은 7.4.2였다... ..... 😥
  2. N의 Minimum API Level은 24였고, C는 22였다.

그걸 말씀드리자 cto님이 그럼 일단 gradle 문제는 아니라고 말씀하셨고, 나도 그런것같았다..

그리고 N에서는 사용하지 않고 C에서 사용하는게 있었는데, 페이스북 sdk였다.

그리고 화면공유로 보여주신 화면에 minimum API Level을 올리면 된다는 글을 보았다.(링크는 찾으면 올리겠다.)


해결


Minimum API Level가 기존에는 22로 설정돼있었는데, 24로 바꾸어서 빌드하니 성공했다.

한것에 비해 해답은 허무했지만, 너무 다행이다.

 

 


작성일: 2024년 8월 1일



for (int i = 0; i < toggles.Length; i++)
{
    toggles[i].btn.onClick.AddListener(() => OnToggle(i));
}

처음 내가 작성했던 코드이다. 코드는 단순해서 따로 설명은 안하겠다..

내가 생각한 대로라면, toggles[0]을 클릭시 OnToggle(0)이 실행되고,
toggles[1]을 클릭시 OnToggle(1)이 실행됐어야 했다.

근데 뜬금없이 button들에서 toggles[5]가 실행되고있었다.


원인

()=> OnToggle(i)

위에서 람다식 안에 들어간 i는 for문에서 사용되는 외부 변수이다.

람다식이 실제 실행되기 이전에는 변수를 참조 형태로 가지고 있다.

버튼들에 들어간 함수는 OnToggle(0), OnToggle(1) 이 아니라
OnToggle(i) 이다. 값이 들어간것이 아니라 i 자체가 참조된것이다.

i는 반복문의 첫번째 사이클에서는 0이었지만,다음에는 1,2,3,4.. 이렇게 자꾸 바뀌는 외부 변수다.

toggles.Length는 5이고, 반복문에 의해 i는 0에서5까지 증가하지만
i < toggles.Length 라는 조건때문에 마지막에는 반복문 안의 함수를 실행하지는 못한 채 탈출한다. (0실행->1실행->2실행->3실행->4실행->5탈출)

이 시점의 i는 5이고, 결국 모든 버튼들에는 OnToggle(5) 가 들어갔던 것이다.


해결

단순하게 반복문 안에 변수를 하나 더 받아서 넣으면 해결이다.

 for (int i = 0; i < toggles.Length; i++)
 {
     var index = i;
     toggles[i].btn.onClick.AddListener(() => OnToggle(index));
 }

꽤 유명한 문제였다. Closure problem 라고 한다고 한다.
https://stackoverflow.com/questions/271440/captured-variable-in-a-loop-in-c-sharp

Invalid username or password.
fatal: Authentication failed for ~

소스트리에서 푸쉬를 시도하면 이런 오류가 뜨는 경우가 있다.
별 일 아니고 깃에서 사용중인 토큰의 기간이 만료된것이다. 새로 생성해주면 된다.

1.깃허브 - Settings 클릭

2.좌측 메뉴에서 DeveloperSettings 클릭

3.Tokens(Classic) 클릭

4.토큰 새로생성


5.Note에 토큰의 이름을 설정해주고, SelectScopes에서 repo만 선택 후 맨아래 Generate Token 클릭


6.토큰생성 완료. 혹시 모르니 따로 저장해두자.


7.소스트리 프로그램 종료시킨 후, 패스워드 파일 삭제
파일경로는 보통 C:\Users\USER\AppData\Local\Atlassian\SourceTree\passwd 이다.
(AppData가 안보인다면 숨김파일 보이기)

8.소스트리 실행. 다시 푸쉬 시도시 아래같은 창 뜸. PW에 6에서 받은 토큰 붙여넣기.

9.끝


얼마나 오랫동안 놀았으면 그새 토큰이 만료 됐을까... 진짜 반성하자 ㅠㅠ

 


작성일: 2023년 7월 19일

+ Recent posts