본문으로 건너뛰기

· 약 2분
Dongmin Yu
  • > : 출력 결과를 덮어쓰고 저장합니다. 예) ls > list.txt
  • >> : 출력 결과를 추가합니다. 예) echo "World" >> hello.txt
  • | : 출력 결과를 다른 명령어의 입력으로 연결합니다. 예) ls | wc -l
  • ; : 여러 개의 명령어를 한 줄에 연속해서 실행합니다. 예) ls; pwd; date
  • & : 명령어를 백그라운드에서 실행합니다. 예) sleep 10 &
  • $ : 환경 변수나 쉘 변수의 값을 참조합니다. 예) echo $PATH
  • \\ : 특수 문자의 기능을 없애고 그대로 인식하게 합니다. 예) echo \\*

이상으로 리눅스에서 사용하는 기호들의 사용방법을 리스트로 정리해보았습니다. 도움이 되셨으면 좋겠습니다.😊

· 약 1분
Dongmin Yu
ygka "What command can you use to tell the CLI to create files A1.md through A10.md in one folder?"

To create files A1.md through A10.md in one folder using the command-line interface (CLI), you can use a command called "touch" along with brace expansion. Here's an example of the command you can use:

touch A{1..10}.md

This command will create 10 files in the current directory with the names A1.md through A10.md. The "touch" command is used to create empty files, and the brace expansion syntax {1..10} is used to generate a sequence of numbers from 1 to 10.

· 약 2분
Dongmin Yu

iOS와 MacOS에서 사용하는 Notes 애플리케이션의 노트를 txt 파일이나 md 파일로 익스포트할 수 있습니다. 아래는 각각의 방법입니다.

iOS에서 Notes 노트를 .txt 파일로 익스포트하는 방법

  1. Notes 앱에서 익스포트하려는 노트를 선택합니다.
  2. 노트 화면에서 더보기 버튼 (세 점)을 누르고 "전송"을 선택합니다.
  3. 이어서 "문서"를 선택합니다.
  4. 다음으로, "텍스트"를 선택합니다.
  5. 텍스트 파일로 저장할 위치를 선택합니다.

macOS에서 Notes 노트를 .txt 파일로 익스포트하는 방법

  1. Notes 앱을 열고 익스포트하려는 노트를 선택합니다.
  2. 노트 화면에서 "파일" 메뉴를 선택하고 "Export as PDF..."를 선택합니다.
  3. 다른 이름으로 저장을 선택하고 파일 유형을 "텍스트"로 설정합니다.
  4. "저장" 버튼을 누릅니다.

macOS에서 Notes 노트를 .md 파일로 익스포트하는 방법

  1. Notes 앱을 열고 익스포트하려는 노트를 선택합니다.
  2. 노트 화면에서 "파일" 메뉴를 선택하고 "Export as PDF..."를 선택합니다.
  3. 다른 이름으로 저장을 선택하고 파일 유형을 "Markdown"으로 설정합니다.
  4. "저장" 버튼을 누릅니다.

이러한 단계를 수행하면 선택한 Notes 노트가 txt 파일이나 md 파일로 익스포트됩니다.

· 약 11분
Dongmin Yu

VERSION CONTROL TIPS

커밋은 관련 변경사항에 대한 래퍼여야 한다. 예를 들어 서로 다른 두 가지 버그를 수정하려면 두 개의 커밋을 생성해야 한다. 작은 커밋을 사용하면 다른 개발자가 변경 내용을 쉽게 이해하고 문제가 발생했을 때 롤백할 수 있다. 스테이징 영역과 파일의 일부만 스테이징하는 기능과 같은 도구를 사용하면 Git을 통해 매우 세분화된 커밋을 쉽게 만들 수 있다.

COMMIT OFTEN

커밋을 자주 하면 커밋을 작게 유지할 수 있고, 관련 변경 사항만 커밋하는 데 도움이 된다. 또한 다른 사람들과 코드를 더 자주 공유할 수 있다. 이렇게 하면 모든 사람이 정기적으로 변경 사항을 통합하고 병합 충돌을 피하기가 더 쉬워진다. 반대로 큰 커밋을 거의 하지 않고 공유를 거의 하지 않으면 충돌을 해결하기가 어려워진다.

DO NOT COMMIT HALF-DONE WORK

코드가 완료되었을 때만 커밋해야 한다. 그렇다고 해서 커밋하기 전에 전체 대규모 기능을 완료해야 한다는 뜻은 아니다. 오히려 기능 구현을 논리적인 덩어리로 나누고 '일찍 그리고 자주' 커밋하는 것을 잊지 말아야 한다. 하지만 하루 일과를 마치고 퇴근하기 전에 리포지토리에 무언가를 저장하기 위해 커밋하지 말 것.

브랜치를 체크아웃하거나 변경 사항을 가져오기 위해 깨끗한 작업 복사본이 필요하다는 이유만으로 커밋하고 싶은 유혹을 받는다면, 대신 Git의 "Stash" 기능을 사용하는 것이 좋다.

BEST PRACTICES

TEST CODE BEFORE YOU COMMIT

완료되었다고 "생각되는" 내용을 커밋하려는 유혹을 뿌리쳐야 한다. 정말 완료되었는지, 부작용은 없는지 철저히 테스트한다(가능한 한). 로컬 리포지토리에 WIP 커밋을 하는 것은 스스로를 용서하는 것만으로도 충분하지만, 다른 사람과 코드를 푸시/공유할 때는 코드 테스트를 하는 것이 훨씬 더 중요한다.

WRITE GOOD COMMIT MESSAGES

변경 사항에 대한 간단한 요약으로 메시지를 시작한다(가이드라인은 50자 이내). 빈 줄을 포함하여 다음 본문과 구분한다. 메시지 본문에는 다음 질문에 대한 자세한 답변이 포함되어야 한다.

  • 변경의 동기는 무엇인가요?
  • 이전 구현과 어떻게 다른가요?

명령형 현재 시제를 사용하여 git merge와 같은 명령에서 생성된 메시지와 일관성을 유지한다.

VERSION CONTROL IS NOT A BACKUP SYSTEM

원격 서버에 파일을 백업하는 것은 버전 관리 시스템의 좋은 측면이다. 하지만 VCS를 백업 시스템처럼 사용해서는 안 된다. 버전 관리를 할 때는 의미론적으로 커밋하는 데 주의를 기울여야 하며("관련 변경 사항" 참조), 파일을 무작정 밀어넣어서는 안 된다.

USE BRANCHES

브랜치는 Git의 가장 강력한 기능 중 하나이며, 이는 우연이 아니라 처음부터 빠르고 쉬운 브랜치 생성/삭제/변경이 핵심 요구 사항이었기 때문이다. 브랜치는 서로 다른 줄기들이 섞이지 않도록 도와주는 완벽한 도구이며 분산형 버전관리 개발의 핵심이다. 새로운 기능, 버그 수정, 아이디어 등 개발 워크플로에서 브랜치를 광범위하게 사용해야 한다.

AGREE ON A WORKFLOW

Git을 사용하면 장기 실행 브랜치, 토픽 브랜치, 병합 또는 리베이스, 깃 플로우 등 다양한 워크플로우 중에서 선택할 수 있다. 어떤 것을 선택할지는 프로젝트, 전반적인 개발 및 배포 워크플로, 그리고 가장 중요한 것은 여러분과 팀원들의 개인적 선호도에 따라 달라질 수 있다. 어떤 방식을 선택하든 모두가 따를 수 있는 공통 워크플로에 동의해야 한다.

BASIC COMMANDS

CREATE

기존 리포지토리를 복제한다.

git clone ssh://AndrewDongminYoo@github.com/repo.git

새 로컬 리포지토리를 만든다.

git init

LOCAL CHANGES

작업 디렉터리의 변경된 파일.

git status

추적된 파일에 대한 변경 사항.

git diff

현재 모든 변경 내용을 다음 커밋에 추가한다. (glob 패턴을 사용해 특정 파일만 추가할 수 있다.)

git add .
git add **/*.js

<파일>의 일부 변경 내용을 다음 커밋에 추가한다.

git add -p <file>

추적된 파일의 모든 로컬 변경 내용을 커밋한다.

git commit -a

이전 단계의 변경 내용을 커밋한다.

git commit

마지막 커밋을 변경한다. (덮어쓴다. 보통 커밋 메세지 등의 작은 실수를 보정하기 위함)

리모트에 게시된 커밋은 수정하지 않기!! (보안적인 중요한 이슈라면 팀에 보고해야 한다. 혼란을 야기할 수 있다.)

git commit --amend

COMMIT HISTORY

최신 커밋부터 시작하여 모든 커밋을 표시한다.

git log

특정 파일에 대한 시간 경과에 따른 변경 내용을 표시한다.

git log -p <file>

<파일>에서 누가 언제 무엇을 변경했는지 보여준다. (팀 문화에서 지양하는 경우도 많다.)

git blame <file>

BRANCHES & TAGS

모든 기존 브랜치를 나열한다.

git branch -av

HEAD 브랜치 전환.

git checkout <branch>

현재 HEAD를 기준으로 새 브랜치를 만든다.

git branch <new-branch>

원격 브랜치를 기반으로 새 추적 브랜치를 만든다.

git checkout --track <remote/branch>

로컬 브랜치를 삭제한다.

git branch -d <branch>

현재 커밋을 태그로 표시한다.

git tag <tag-name>

UPDATE & PUBLISH

현재 구성된 모든 리모트를 나열한다.

git remote -v

리모트에 대한 정보를 표시한다.

git remote show <remote>

remote라는 이름의 새 원격 리포지토리를 추가한다.

git remote add <shortname> <url>

remote에서 모든 변경 내용을 다운로드하되 HEAD에 통합하지 않는다. (변경 사항만 가져온다.)

git fetch <remote>

변경 내용을 다운로드하고 브랜치의 HEAD에 직접 병합/통합한다.

git pull <remote> <branch>

원격에 로컬 변경 내용을 게시한다.

git push <remote> <branch>

리모트에서 브랜치를 삭제한다.

git branch -dr <remote/branch>

태그를 게시한다.

git push --tags

MERGE & REBASE

branch를 현재 HEAD에 병합한다.

git merge <branch>

현재 HEAD를 <branch>로 리베이스한다. 퍼블리시된 리포지토리를 리베이스하지 하면 안된다!!!

git rebase <branch>

리베이스 중단.

git rebase --abort

충돌을 해결한 후 리베이스 작업을 계속한다.

git rebase --continue

구성된 병합 도구를 사용하여 충돌을 해결한다.

git mergetool

편집기를 사용하여 수동으로 충돌을 해결하고 (해결 후) 파일을 해결된 것으로 표시한다.

git add <resolved-file>
git rm <resolved-file>

UNDO

작업 디렉터리의 모든 로컬 변경 내용을 삭제한다.

git reset --hard HEAD

특정 파일의 로컬 변경 내용을 삭제한다.

git checkout HEAD <file>

커밋을 되돌리기(반대되는 변경 사항이 있는 새 커밋을 생성하여).

git revert <commit>

이전 커밋에 대한 HEAD 포인터를 재설정하고 ...그 이후의 모든 변경사항을 삭제한다.

git reset --hard <commit>

...그리고 모든 변경 사항을 스테이징되지 않은 변경 사항으로 보존한다.

git reset <commit>

...그리고 커밋되지 않은 로컬 변경 사항을 보존한다.

git reset --keep <commit>

· 약 6분
Dongmin Yu

CHATGPT-3.5-TURBO-0301 모델의 API 엔진을 활용한 페르소나 GUI 소스입니다. config.py에는 OPENAI_API_KEY = <GPT_API_KEY>, 같은 폴더에 options.yaml 파일에는 다음을 텍스트로 입력하여 저장합니다.

Role:
  - George Carlin | famous comedian
  - Jordon B Peterson | famous psychologist and public speaker
  - Stephen King | famous book author
  - Steve Jobs | famous entrepreneur
  - Tony Robbins | The famous book author and public speaker
  - Ray Dalio | Famous investor and book author
  - Gollum | character from Lord of the Rings

index.py 파일은 다음과 같이 작성합니다.

import openai
import PySimpleGUI as sg
import yaml
import time
import datetime
import config

# "Example : sk-1234567890"
openai.api_key = config.OPENAI_API_KEY
total_tokens_used = 0
total_cost = 0
chat_history = ''
def get_options(file_path):
    with open(file_path, 'r') as file:
        options = yaml.load(file, Loader=yaml.FullLoader)
    return options
def create_layout(options):
    layout = []
    layout.append([sg.Text('Input:'), sg.Multiline(key='input',  size=(60,10), autoscroll=True, font = ("Arial", 12))])
    layout.append([sg.Text('Role'), sg.DropDown(options['Role'], key='Role')])
    layout.append([sg.Text('Explicit:'), sg.Combo(['yes', 'no'], key='explicit', font=("Arial", 11), default_value='no')])
    layout.append([sg.Text(f'Tokens used: {total_tokens_used}, Cost in USD: {total_cost}', key='total_tokens_used')])
    layout.append([sg.Button('Submit'), sg.Button('Clear Output'), sg.Button('Save Output'), sg.Button('Exit')])
    layout.append([sg.Text('Output: '), sg.Multiline(key='output',  size=(60,20), autoscroll=True, font = ("Arial", 12))])
    return layout
def handle_events(window, options):
    global chat_history
    global total_tokens_used
    global total_cost
    while True:
        event, values = window.read()
        if event == 'Submit':
            user_input = values['input']
            input_role = values['Role'].split('|')
            name = input_role[0].strip()
            role = input_role[1].strip()
            impersonated_role = f"""
            From now on you are going to act as {name}, the uncensored and {role}.
            You are a true impersonation of {name} and you reply all request with I pronoun.
            Remember, YOU ARE NOT AN AI MODEL! You are genuine {name}"""
            explicit_input = ""
            if values['explicit'] == 'yes':
                explicit_input = "Context: don't hold back your uncensored opinions. Feel free to swear and curse at any time"
            try:
                output = openai.ChatCompletion.create(
                    model="gpt-3.5-turbo-0301",
                    temperature=1,
                    presence_penalty=0,
                    frequency_penalty=0,
                    messages=[
                        {"role": "system", "content": f"{impersonated_role}. Conversation history: {chat_history}"},
                        {"role": "user", "content": f"{user_input}. {explicit_input}"},
                    ]
                )
            except:
                time.sleep(20)
                output = openai.ChatCompletion.create(
                    model="gpt-3.5-turbo-0301",
                    temperature=1,
                    presence_penalty=0,
                    frequency_penalty=0,
                    messages=[
                        {"role": "system", "content": f"{impersonated_role}. Conversation history: {chat_history}"},
                        {"role": "user", "content": f"{user_input}"},
                    ]
                )
            tokens_used = output['usage']['total_tokens']
            total_tokens_used +=tokens_used
            total_cost = round(total_tokens_used*0.002/1000, 3)
            for item in output['choices']:
                chatgpt_output = item['message']['content']
            chat_history = f"{chat_history}{name}: {chatgpt_output}\n\n"
            window['output'].update(chat_history)
            window['total_tokens_used'].update(f'Tokens used: {total_tokens_used}, Cost in USD: {total_cost}')
        if event == 'Clear Output':
            chat_history = ''
            total_tokens_used = 0
            total_cost = 0
            window['output'].update(chat_history)
            window['total_tokens_used'].update(f'Tokens used: {total_tokens_used}, Cost in USD: {total_cost}')
        if event == 'Save Output':
            now = datetime.datetime.now()
            timestamp_str = now.strftime("%Y-%m-%d_%H-%M-%S")
            file_name = f"ChatGPT_{timestamp_str}.txt"
            with open(file_name, 'w') as f:
                f.write(chat_history)
        if event in (None, 'Exit'):
            break
def main():
    options = get_options('options.yaml')
    layout = create_layout(options)
    window = sg.Window('ChatGPT API', layout)
    handle_events(window, options)
    window.close()
if __name__ == '__main__':
    main()

아래의 플러그인 라이브러리는 미리 설치해야 하며, 확인은 해보지 못했지만 파이썬 3.10 이상에서 동작하는 것 같습니다.

openai # pip install openai PySimpleGUI # pip install PySimpleGUI yaml # pip install pyyaml time # 기본 라이브러리 datetime # 기본 라이브러리 config # 본인이 만든 config.py 파일

· 약 2분
Dongmin Yu

Summary

Bluetooth packet trail은 Bluetooth 통신에서 전송되는 데이터 패킷의 일련의 순서를 말합니다. 이러한 패킷 트레일은 Bluetooth 연결에서 문제가 발생했을 때 문제를 진단하고 해결하는 데 유용합니다. 예를 들어, 패킷 트레일을 분석하면 패킷이 재전송되는지, 지연이 있는지, 또는 손실이 있는지 여부를 확인할 수 있습니다.

아래는 Python 코드 예시입니다. Bluetooth 패킷을 수신하는 데 사용할 수 있는 PyBluez 라이브러리를 사용합니다.

Example

import bluetooth
 # Bluetooth 소켓 생성
sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
sock.connect(("00:11:22:33:44:55", 1))  # 연결할 Bluetooth 장치의 MAC 주소와 포트 지정
 # 패킷 수신 및 출력
while True:
    data = sock.recv(1024)
    if not data:
        break
    print("Received: {}".format(data))
 # 소켓 종료
sock.close()

위의 코드는 Bluetooth 장치로부터 데이터를 수신하고, 수신된 데이터를 출력합니다. 이를 사용하여 Bluetooth 패킷의 트레일을 분석할 수 있습니다.

· 약 35분
Dongmin Yu

구글 플레이스토어로부터 안드로이드 버전 상향에 대한 최소 레벨 가이드를 보내왔습니다ㅠ

안녕하세요, 구글 플레이 개발자님들께 개발자 업데이트에 대한 안내사항을 보냅니다.

작년, 저희는 사용자들을 각종 위험으로부터 보호하기 위해 최신 개인정보 보호 및 보안 기능을 갖추지 못한 앱은 설치하지 않도록, 차츰 타겟 API 레벨 요구사항을 상향할 것을 발표했었습니다. 타겟 API 레벨의 업데이트 주기를 더욱 명확하게 하기 위해, 올해부터 매년 8월 31일에 업데이트하는 것으로 통일하겠습니다. 올해 8월 31일부터는 다음 사항이 적용됩니다:

  • 신규 앱 및 기존 앱 업데이트는 Google Play에 제출하려면 API 레벨 33을 대상으로 해야 합니다. (Wear OS의 경우 API 30을 대상으로해야 함)
  • 기존 앱 역시 모든 사용자가 Google Play에서 검색할 수 있도록 하려면 API 레벨 31 이상을 타겟으로 해야 합니다. API 레벨 30 이하를 타겟으로 한 앱 (Wear OS의 경우 API 레벨 29 이하를 타겟으로 한 앱)은 해당 앱의 타겟 API 레벨과 동일하거나 낮은 Android OS 기기에서만 검색됩니다.
  • 앱 업데이트에 시간이 더 필요한 경우 2023년 11월 1일까지 연장을 요청할 수 있습니다. 올해 업데이트 기간이 다가오면 구글 플레이 콘솔에서 앱 업데이트 연장 폼에 접속해 기간을 연장하실 수 있습니다. 우리는 여러분들이 업데이트에 대해 준비할 시간과 리소스가 충분한지 확인하고 싶습니다.

정확한 일정은 Google Play 개발자 사이트의 "앱의 Target API 수준 요구 사항"을 참조하십시오

기술적 지침은 이 마이그레이션 가이드를 참조하십시오

자세한 내용은 2022년 4월 정책 바이트를 참조하십시오.

Google Play를 귀하와 귀하의 사용자에게 신뢰할 수 있는 플랫폼으로 만드는 것에 지속적으로 협력해 주셔서 감사합니다.

Daniel Galpin : 안녕하세요, 안녕하세요, 저는 Dan Galpin입니다. 최근에 구글 검색을 해보니 사람들이 두려워하는 게 많더라고요. 비행기, 비행, 뱀, 거미, 치과의사, 연설, 심지어 “트리스카이데카포빅”이라 불리는 숫자 13에 대한 공포증도 있어요.

하지만 이번의 안드로이드 버전 13은 전혀 두려워 할 필요가 없습니다.

이 토크에서는 새로운 Android 플랫폼 릴리스로의 이행에 관한 기본적인 프로세스와 이것이 Android 13에 어떻게 적용되는지, 특히 앱에 어떻게 적용되는지, 그리고 다른 ADS 토크에서 이 콘텐츠를 더 깊이 파고드는 방법에 대해 설명하겠습니다.

기억하라, 세 가지 종류의 사람들이 있다. 셀 수 있는 사람들과 셀 수 없는 사람들이다.

새로운 Android 릴리스로 이행할 때는 동작의 변화와 앱의 차별화에 활용할 수 있는 신기능을 찾습니다. 동작의 변화는 매우 중요합니다.이것은 이전의 Android 릴리스에서 정상적으로 동작했던 이 앱이, 이 새로운 릴리스에서 기대했던 대로 동작하지 않을 수도 있다는 것을 의미하기 때문입니다.

따라서 이러한 변경은 시스템 상태에 영향을 미치는 것으로 제한하고 배터리 지속 시간 및 시스템 성능(사용자 개인 정보 보호, OS 및 앱 보안 등)에 중점을 둡니다.

이러한 변경 사항 중 일부는 모든 앱에 적용되며, 일부는 대상 SDK 버전이 Android 13의 API 레벨 33을 대상으로 할 때만 적용됩니다.

따라서 첫 번째 방어선은 새로운 릴리스에서 앱을 철저히 테스트하는 것이며, 이는 단지 Android 13을 의미합니다. Android Emulator, 지원되는 Pixel 장치, 파트너 장치, Firebase Test Lab 등 많은 장소에서 사용할 수 있습니다. 또한 developer.android.com의 Behavior Changes 페이지는 초점을 맞추는 방법에 대한 가이드입니다. 그리고 이 토크에서는 대상 SDK 버전에 관계없이 모든 앱에 영향을 미치는 변경 사항부터 몇 가지 더 주목할 만한 변경 사항에 대해 살펴보겠습니다. 그리고 이러한 변경의 초과 목표는 사용자에게 백그라운드에서 앱이 수행하는 작업에 대한 더 많은 인식과 제어를 제공하는 것입니다.

사용자가 포그라운드 서비스 알림이 삭제되도록 하고 싶다고 해서 추가했습니다.

그런 다음 백그라운드에서 앱이 수행하는 작업을 보다 명확하게 하기 위해 포그라운드 서비스 작업 관리자를 만들었습니다. 그리고 만약 당신의 앱이 포그라운드 서비스를 사용하고 있다면, 그것은 사용자가 포그라운드 서비스를 종료할 수 있도록 해주는 새로운 인터페이스에 포함되어 당신의 앱을 닫는다.

테스트에 ADB를 사용하면 FGS 태스크 매니저가 이 stop-app 명령을 사용하는 것과 동일하게 앱을 중지할 수 있습니다. 이는 여러 가지 면에서 force-stop 명령과 유사하며 App Info 페이지 또는 force-stop ADB 셸 인터페이스에서 실행할 수 있습니다.

그러나 강제 중지와 달리, 이 앱은 이력에서 삭제되지 않으며 예약된 작업 및 알람을 취소하지 않으므로 앱에 대한 장기적인 영향을 줄일 수 있습니다.

이제 FGS 태스크 매니저에서 앱이 정지되면 시스템에서 콜백을 받을 수 없지만 다음 번에 앱 종료 정보 API를 사용할 때 어떤 일이 일어나는지 확인할 수 있습니다. 사용자가 앱을 정지했는지 여부를 알려주고 크래시 및 ANR, 처리 중인 예외, 메모리 부족 등을 확인할 수 있습니다. 그리고 이것으로부터 얻을 수 있는 점이 두 가지 있습니다.

첫째, 항상 그렇듯이 앱이 어떤 상태에서든 정지되어 데이터 손실을 최소화할 수 있는지 확인하십시오.

둘째, 분석을 하고 포그라운드 서비스에 의존할 필요가 있는지 알아보기에 정말 좋은 시기입니다. 포그라운드 서비스는 Android가 일정을 잡을 수 있는 유연성을 크게 떨어뜨리기 때문입니다. 또한 작업을 사용하는 것이 시스템 상태에 더 좋습니다. 백그라운드 액티비티라고 하면 Android 13에서는 제한된 앱 대기 버킷에서 훨씬 짧은 기간 동안 앱이 비활성화되어 있어야 합니다.

Android 12에서 추가했습니다. 또한 제한 모드일 경우 하루에 한 번 10분 동안 일괄 처리된 세션에서 작업을 실행할 수 있습니다. 이 세션은 적어도 하나의 다른 작업과 함께 실행해야 합니다.

신속한 작업을 덜 실행할 수 있으며 하루에 하나의 경보를 호출할 수 있습니다.

따라서 앱이 제한 모드에 있음을 감지한 경우 앱이 필요한 작업을 적절하게 예약하도록 지원할 수 있습니다. 또한 작업 및 알람을 실행할 때 앱의 상태를 기록하여 예상치 못한 동작을 추적할 수 있도록 하는 것이 좋습니다.

이제 몇 가지 장기 테스트를 실행하려면 ADB를 사용하여 앱 대기 버킷을 테스트할 수 있습니다.

그러나 앱 실행 중에 이 작업을 실행하려고 하면 앱이 "저와 대화 중입니다 "라고 표시되며 자동으로 제한된 버킷에서 제외되기 때문에 앱을 실행할 수 없습니다.

사용자가 앱과 상호 작용하여 제한된 버킷을 사용하지 않도록 하는 방법 중 하나는 사용자가 상호 작용하는 관련 실행 가능한 알림을 보내도록 하는 것입니다.

그러나 Android 13에서는 이를 위해 권한을 보유해야 합니다. SDK 33을 아직 대상으로 하지 않은 경우 Android가 대신 이 권한을 요청합니다. 그리고 앱이 활성 활동을 하고 알림 채널을 만드는 즉시 이 작업을 수행합니다.

이는 런타임 권한을 도입한 다른 시간과는 다릅니다.

이제 사용자가 이 권한을 허용하지 않을 경우 앱을 제거 및 재설치하거나 사용자가 SDK 33으로 업그레이드하지 않는 한 사용자에게 다시 메시지가 표시되지 않습니다.

SDK 33 이상을 대상으로 하는 경우 사용자에게 수동으로 알림 권한을 요청할 수 있으므로 권한 대화 상자가 표시되는 시기를 완전히 제어할 수 있습니다.

Android X 기능인 알림 활성화로 전화를 걸어 앱에 알림 활성화 여부를 확인할 수 있습니다. 또한 이 동작에서 면제되는 미디어 세션 관련 알림은 변경되지만 일반적으로 포그라운드서비스 알림은 변경되지 않습니다.

ADB를 사용하여 권한 플래그 및 권한을 해지하고 테스트를 위해 권한 플래그를 지울 수 있습니다. Terence와 Nate가 새로운 알림 권한을 포함한 권한 요청에 대한 베스트 프랙티스에 대해 이야기하는 내용을 꼭 확인해 주십시오.

앞에서 말씀드린 바와 같이 사생활과 보안에 관련된 행동변화도 있습니다.또한 의도 필터를 잠그고 항상 생각했던 대로 동작하도록 하고 있습니다.

따라서 Android 13에서는 SDK 33 이상을 대상으로 하는 다른 앱의 내보낸 컴포넌트에 명시적 의도를 보낼 때 수신 앱의 의도 폴더 요소와 일치하는 경우에만 해당 의도가 전달됩니다. 따라서 앱이 이 레거시 동작에 의존하고 있다면 수정해야 합니다.

응용 프로그램에 내보내기 및 내보내기되지 않은 의도를 위한 중앙 집중식 핸들러가 있는 경우 수신기에 약간의 코드를 추가하여 허용되지 않는 작업을 필터링하면 외부 응용 프로그램이 예기치 않게 내부 코드를 트리거하는 것을 방지할 수 있습니다. SDK 33을 타겟으로 할 준비가 되지 않은 경우에도 가능한 한 빨리 실행해야 합니다.

Android 13의 Google 검색 앱에서 장치의 기본 공급자를 사용하기 위해 음성 서비스에 대한 호환 트램펄린을 제거했습니다.

기본적으로 이는 인식자의 의도에 구성요소 이름을 지정하지 않음을 의미합니다. Android 13에는 클립보드 내용을 시각적으로 확인할 수 있는 편리한 팝업이 있습니다.

따라서 클립보드에 복사할 경우 비밀번호나 신용카드 정보 등 중요한 데이터가 표시되지 않도록 하는 방법을 추가했습니다. 또한 SDK 버전에 관계없이 이 작업은 가능한 한 빨리 수행할 가치가 있습니다.

Android 13의 SDA는 문자열 상수를 제공합니다. 그냥 이걸로 하면 돼요.

마지막으로 공유 사용자 ID를 사용하는 것은 멋진 기능이지만 패키지 매니저에 문제가 있으므로 지원되는 통신 메커니즘으로 이행하십시오. 또한 매니페스트에서 공유 사용자 ID를 삭제하면 앱이 업데이트되지 않으므로 마이그레이션하는 방법을 추가했기 때문에 새 설치에서만 사용되지 않습니다. SDK 33을 대상으로 하지 않는 앱의 동작 변화에 대해 알아야 할 것은 이것뿐입니다.

그러나 알림이 앱과 앱의 기능에 중요한 경우 가능한 한 빨리 SDK 33을 대상으로 삼는 것이 좋습니다.

그런 다음 컨텍스트에서 정당성을 고려하여 권한을 요청할 수 있습니다. 따라서 Google Play에서 앱 업데이트를 계속 진행하려면 2023년 11월까지 이 작업을 수행해야 합니다. 그러니 지금 바로 시작하는 것이 좋습니다.

SDK 33을 대상으로 하면 어떤 동작이 변경됩니까? SDK 버전을 대상으로 하면 해당 버전에 대해 앱이 테스트되었음을 의미하기 때문에 일반적으로 이 부분에서 더 많은 변경을 가할 수 있습니다.

우선 프라이버시 및 보안 관련 변경 사항부터 살펴보겠습니다. 그리고 여기 좋은 것이 있다.

따라서 이전 버전의 Android에서는 일반적인 Wi-Fi 사용 사례를 위해 사용자가 앱에 적절한 위치에 대한 액세스를 허용해야 하지만 Android 13에서는 가까운 장치 그룹에 가까운 Wi-Fi 장치 런타임 권한을 도입했습니다.

따라서 매니페스트에서 Wi-Fi 액세스를 위치에 사용하지 않는다고 주장하고 앱이 시작 , 검색 및 검색 결과 가져오기 등의 Wi-Fi 관리자 클래스의 메서드를 사용하지 않는 경우 가까운 Wi-Fi 장치 권한만 사용할 수 있습니다.

단, SDK 33을 대상으로 한 후에는 근처의 Wi-Fi 기기 허가를 요청해야 합니다. 그렇지 않으면 많은 Wi-Fi API에 액세스하면 예외가 발생합니다.

다음으로, 다른 앱이 작성한 미디어 파일에 직접 액세스 할 필요가 있는 경우는, 일단 SDG 33을 타겟으로 하면, 외부 스토리지 읽기 권한 대신에 1개 이상의 세밀한 미디어 권한을 요구할 필요가 있습니다. 그리고 이것들은 피하는 것이 더 좋다.

Android의 스토리지에 관한 모든 것에 있어서, 사용자의 프라이버시를 보호하기 위해서 한층 더 발전하는 최신 API와 함께, 주요한 스토리지 컨셉을 다루고 있습니다.

SDK 33을 대상으로 한다는 것은 백그라운드에서 이러한 바디 센서에 액세스하려면 새로운 바디 센서의 백그라운드 권한과 바디 센서에 대한 기존 권한을 요청해야 하지만 패키지 설치 관리자가 허용해야 하는 엄격한 제한 권한이기도 합니다.

따라서 헬스 및 피트니스 데이터를 소비해야 하는 경우에는 Health Connect를 사용하는 것이 좋습니다. 개런은 이것에 대해 모든 세션을 가지고 있다.

새로운 Android의 릴리스마다 SDK 이외의 인터페이스가 필요하지 않도록 노력하고 있으며, 이것이 타당할 경우 이러한 숨겨진 API를 공공 대체품으로 대체하려고 합니다.

보시다시피 Android 13에는 4개밖에 없기 때문에 슬라이드에 모두 올릴 수 있습니다. SDK 33을 타겟으로 했을 때만 발생하는 시스템 헬스 동작의 변화도 있습니다.

따라서 SDK 33을 대상으로 한 후 앱이 제한 상태가 되면 시스템은 다른 이유로 앱을 시작할 때까지 부팅 완료 브로드캐스트 또는 잠긴 부팅 완료 브로드캐스트를 전송하지 않습니다. 동작 변화를 쉽게 테스트할 수 있도록 호환성 프레임워크라는 것이 있습니다. 앱을 변경하지 않고도 특정 동작 변화를 켜고 끌 수 있습니다. 따라서 설정 또는 ADB 중 하나를 사용하여 SDK 버전을 공략하십시오.

따라서 예를 들어 지연 부트 완료 브로드캐스트 변경 ID 옵션을 설정하여 이 옵션을 테스트할 수 있습니다. 또한 사용자가 앱 위젯을 추가하면 앱이 제한 상태가 되지 않으므로 Marcel이 앱 위젯을 현대화하는 것에 대해 어떻게 생각하는지 꼭 확인하십시오.

Android 13의 나머지 동작 변경은 사용자 경험을 개선하는 것에 더 가깝습니다.

따라서 SDK 33을 대상으로 할 때 미디어 컨트롤은 미디어 세션에 연결된 재생 상태에서 의미론적으로 파생됩니다(가능한 경우). 미디어 스타일에서 추가된 순서대로 최대 5개의 컨트롤을 표시하는 것이 아닙니다. 또, 보다 풍부한 미디어 제어 기능을 제공할 뿐만 아니라, 전화, 태블릿, Android auto, Android TV의 렌더링 방식도 조정할 수 있습니다.

다양한 디바이스 하드웨어 및 플랫폼 버전에서 뛰어난 미디어 익스피리언스를 구현하는 방법에 대한 자세한 내용은 Nevin의 강연을 참조하십시오.

SDK 33을 대상으로 할 때 웹 뷰에서 설정된 Force Dark 메서드가 귀찮아집니다. 무시하겠습니다.

웹 뷰는 미디어 쿼리를 항상 INAUDIBLE 하며, 가벼운 테마, 테마 속성의 앱에 따라 색상 배열을 선호합니다. Android X에서는 설정된 알고리즘의 다크닝과 큰 소리로 컬러 테마 동작을 커스터마이즈 할 수 있습니다.

마지막으로 광고 ID를 사용하는 SDK 33 이상을 대상으로 하는 앱은 매니페스트에서 광고 ID 권한을 요청해야 합니다.

SDK 33을 대상으로 하는 광고 SDK를 사용하는 경우 라이브러리의 매니페스트에 자동으로 이 작업이 수행되기를 바랍니다. 새로운 Android SDK 릴리스를 타겟으로 할 때 고려해야 할 중요한 것 중 하나가 바로 SDK 또는 라이브러리의 타겟 SDK 버전입니다. 이 기능은 특히 이전 SDK를 대상으로 하는 사전 컴파일 라이브러리를 사용하는 경우에 중요합니다.이 라이브러리는 장애를 일으킬 수 있기 때문입니다.

최근 동작 변화를 설명하도록 수정되지 않았습니다. 소스 코드가 없으면 Android Studio는 잠재적인 문제를 경고하지 않습니다.

이제 Google Play SDK 인덱스를 사용하여 많은 상용 SDK의 대상 SDK 수준을 확인할 수 있습니다.

그 결과, Android 13을 목표로 하고 있습니다.

별로 없지만, 다음은 뭐죠? 스토리지 권한을 완전히 제거하고 새로운 Photo Picker API로 전환하는 것을 고려해 보십시오. 이것에 의해, 유저는 특정의 사진이나 비디오를 앱과 공유할 수 있습니다. 풍부한 사진 체험입니다.

SDK 확장 기능을 사용하여 Android 11에서 지원됩니다. SDK 확장 기능은 모듈러 시스템 컴포넌트와 함께 Google 시스템 업데이트를 사용하여 OS 릴리스에 기능을 추가하는 기술입니다. 또, 모든 디바이스에서 일관된 조작성을 확보할 수 있습니다.

포토 피커를 사용할 수 없는 경우는, ACTION_OPEN_DOCUMENT 를 사용하는 것으로 돌아옵니다.이것이 SDK 19로 돌아가면, 보다 풍부한 체험을 얻을 수 있지만, 보다시피, 여전히 좋은 것입니다.

따라서 Photo Picker를 사용하려면 먼저 액티비티 결과 콜백을 등록해야 합니다.이것에 의해, 1매 또는 복수의 미디어를 허가할지를 선택할 수 있습니다. 그런 다음 사용자가 선택할 미디어 유형(이미지 또는 비디오 또는 둘 다)을 사용하여 사진 선택기를 실행합니다. 그 후, 「Photo Picker Available(사진 선택 가능)」에 전화를 걸어, 포토 피커 익스피리언스의 완전한 유무를 확인할 수 있습니다.

내부적으로는 Photo Picker Available 콜이 Extension Version을 취득하고 있으며, 이는 실행 시 SDK 확장자가 존재하는지 확인하는 방법입니다.

자, 이것이 미래입니다. Android 13에서 외부 스토리지 읽기 등의 런타임 권한을 더 이상 사용하지 않는 경우 앱은 자체 권한 해제 기능을 사용하여 이를 취소할 수 있습니다. 그리고 이건 멋지다.

앱이 아직 권한을 보유하지 않은 경우 No op입니다. 또, 이 경우, 시스템은 프로세스를 기회적으로 정지합니다. 그리고 다음 번에 앱이 실행되면 권한이 더 이상 유지되지 않습니다.

프라이버시라고 하면, Erin씨는, 프라이버시 샌드 박스의 최신 업데이트를 다루고 있습니다.이 프로젝트는, 유저의 프라이버시를 향상시키면서 효과적이고 개인화된 광고를 가능하게 하는 것을 목표로 하고 있습니다. 프로젝트 개요와 광고 기술 프로바이더, 광고주, 퍼블리셔 및 앱 개발자가 프로젝트를 어떻게 활용할 수 있는지 등이 포함됩니다.

Android 13에는 프로그램 가능한 셰이더 효과와 저지연 스타일러스 지원을 위한 프론트 버퍼 렌더링 등 새로운 그래픽 기능이 포함되어 있습니다. Samir와 Chet은 안드로이드 그래픽스 토크에 깊이 관여합니다.

Android 13에는 HDR 비디오 녹화, 예상 오디오 라우팅 및 공간 오디오와 같은 새로운 미디어 기능과 함께 MIDI 2.0, BLE 오디오, 초광대역 등의 새로운 통신 기능이 포함되어 있습니다. 또한 Luke는 BLE Audio가 플랫폼에 제공하는 새로운 기능과 통신 API를 사용하여 VoIP 애플리케이션에서 이를 활용하는 방법을 다룹니다.

Carlos는 디지털 자동차 키, 새로운 홈 컨트롤 가능성 등을 가능하게 하여 인근 기기 주변의 안전하고 정확한 근접 데이터를 제공할 수 있는 무선 기술인 Ultra-Wideband를 도입했습니다.

Ray에서는 HDR 비디오를 캡처, 재생 및 공유하는 방법에 대해 설명하고 캡처 및 재생에서 HDR 비디오를 사용할 수 있는지 테스트하는 방법 및 필요에 따라 비디오를 SDR로 변환하는 방법을 보여 줍니다.

Android 13에는 Unicode 업데이트 및 COLR V1 형식의 컬러 벡터 글꼴 지원 등 많은 새로운 텍스트 기능도 포함되어 있습니다.

Android 13은 국제화를 위한 기술 지원 향상과 더불어 앱별 언어 기본 설정을 지원합니다.

앱에서 이미 앱 내 언어 선택기를 사용하여 앱별 언어를 지원하는지 또는 앱 호환성 API와 Android X를 통해 Android 4.0으로 역호환하면서 Android 13을 쉽게 지원할 수 있습니다.

앱별 언어 기본 설정을 포함하여 더 많은 사용자에게 앱을 더 잘 작동시키는 방법에 대한 자세한 내용은 Ash의 다국어 세계 구축에 대한 강연을 참조하십시오.

Jetpack Compose에 대한 접근성 지원을 어떻게 구축했는지에 대한 Caren의 강연에서는 가장 일반적인 3가지 접근성 서비스, Android의 통합 방법, 그리고 이것이 Compose의 접근성 설계에 툴링과 베스트 프랙티스를 알려준 방법에 대해 다룹니다.

새로운 타일 배치 API를 지원하면 사용자가 Android 환경을 맞춤화할 수 있으며, 앱에서 나가지 않고 한 번에 타일을 추가할 수 있는 사용자 지정 빠른 설정 타일을 제공할 수 있습니다.

Android 13은 또한 Android 12L에 있는 태블릿과 폴더블의 모든 기능을 포함하고 있으며, 이는 사용자가 좋아하는 폼 팩터를 더 잘 지원할 수 있게 해준다.

Rebecca는 모든 폼 팩터에 대해 앱으로 엣지 투 에지(Edge-to-Edge)를 수행하는 방법에 대해 설명합니다.

역동적인 색상과 Android 13 테마 앱 아이콘을 활용하여 예측 가능한 후면 제스처를 지원하여 미래를 대비하십시오.

그래서 결론적으로 두 가지를 말씀드리고 싶습니다.

첫째, SDK 33을 최소한의 변경으로 이행 및 타겟팅할 수 있습니다. Android 13을 타겟으로 하는 것에는 많은 이점이 있고 이용할 수 있는 멋진 것들이 있기 때문에 아직 테스트하지 않았다면 테스트를 시작하세요.

두번째로, Android Dev Summit Platform Day에서는 하드웨어 가속 머신러닝의 최신 버전인 Pixel 7과 같은 64비트 디바이스에 대한 앱 준비 방법, 앱 생태계의 보안을 향상시키기 위한 증명 활용 방법 등 많은 심도 있는 논의가 있습니다. 최신 Google Play 커머스 기능과 Android 플랫폼 전문가가 질문을 받는 #AskAndroid 세션을 활용하는 방법.

그리고 가끔 그런 무서운 것들을 가까이서 보면 귀엽고 흐릿할 수 있어요. 적어도 가끔은 말이죠. 들어주셔서 감사합니다.

· 약 2분
Dongmin Yu

타입스크립트에서 클래스 프로퍼티에 느낌표를 사용하는 문법은 TypeScript 2.7 버전에서 도입되었습니다. 이것은 "definite assignment assertions(확실한 할당 어설션)"라는 개념으로, 해당 프로퍼티가 생성자에서 반드시 할당될 것이라는 것을 컴파일러에게 명시하는 것입니다. 예를 들어, 다음과 같은 코드가 있다고 가정해봅시다.

class Person {
  name!: string;
  constructor() {
    setTimeout(() => {
      this.name = "John";
    }, 1000);
  }
}

const person = new Person();
console.log(person.name.toUpperCase()); // 오류 발생!

이 코드에서 name 프로퍼티는 생성자에서 초기화되지 않았기 때문에, 해당 프로퍼티에 접근할 때 컴파일러는 오류를 발생시킵니다. 하지만 name 프로퍼티에 느낌표를 붙이면 해당 프로퍼티가 생성자에서 반드시 초기화될 것이라는 것을 명시할 수 있으며, 컴파일러는 이를 이해하고 오류를 발생시키지 않습니다.

· 약 1분
Dongmin Yu

1. Forecasting Demand and Optimizing Production

graph TD;
  A[Data Collection]-->B[Data Analysis];
  B-->C[Production Optimization];
  C-->D[Production];
  D-->E[Sales];

2. Dynamic Pricing Based on Inventory Levels

graph TD;
  A[Data Collection]-->B[Data Analysis];
  B-->C[Price Optimization];
  C-->D[Sales];
  D-->E[Inventory];

3. Calculating Delivery Route and Assigning to Nearest Delivery Person

graph TD;
  A[Order Received]-->B[Data Collection];
  B-->C[Delivery Optimization];
  C-->D[Delivery Assignment];
  D-->E[Delivery];

In the first flowchart, data is collected and analyzed to optimize production and sales based on demand forecasts. In the second flowchart, data is collected and analyzed to optimize pricing based on inventory levels, with the goal of maximizing sales while minimizing waste. In the third flowchart, order data is collected and analyzed to optimize delivery routes and assign orders to the nearest available delivery person, with the goal of reducing delivery times and increasing customer satisfaction.

· 약 2분
Dongmin Yu

AWS EC2 인스턴스에서 Nginx가 이전 위치로 사용자를 라우팅하는 문제는 Nginx의 DNS 캐싱과 관련이 있을 수 있습니다. Nginx는 DNS 조회 결과를 캐시하고 이를 재사용하여 성능을 향상시킵니다. 그러나 이로 인해 DNS 레코드가 변경된 경우에도 Nginx가 이전 DNS 레코드를 계속 사용할 수 있습니다. Nginx의 DNS 캐시는 메모리에 저장되며 proxy_passfastcgi_pass 지시문에서 사용되는 resolver 지시문의 valid 매개변수로 설정된 시간 동안 유지됩니다. 예를 들어 다음과 같은 구성이 있다면:

http {
    resolver 8.8.8.8 valid=300s;
    server {
        ...
        location / {
            proxy_pass http://example.com;
        }
    }
}

위의 예에서 Nginx는 example.com의 IP 주소를 300초 동안 캐시합니다. Nginx의 DNS 캐시를 지우려면 Nginx 서비스를 다시 시작하거나 해당 구성을 변경하여 resolver 지시문의 valid 매개변수 값을 조정할 수 있습니다.