๋ฐ์—”์œผ๋กœ ์„ฑ์žฅ์ค‘ ๐ŸŒฑ

๊ฐœ๋ฐœ ์ผ์ง€/[๊ตฌ๋‚ด์‹๋ƒฅ]

์•ฑ ์„œ๋น„์Šค ์šด์˜ ํ•œ ๋‹ฌ ํ›„๊ธฐ

์จ๋ฐ 2023. 6. 27. 17:31

 

 

Android๋Š” 5์›” 18์ผ ์ถœ์‹œ.

iOS๋Š” 5์›” 17์ผ ์ถœ์‹œ.

 

๋ฒŒ์จ ๊ฐ ์Šคํ† ์–ด์— ์•ฑ์„ ์ถœ์‹œํ•œ์ง€ ํ•œ ๋‹ฌ์ด ์ง€๋‚ฌ๋Š”๋ฐ, ๊ทธ ๋™์•ˆ ๊ด€๋ฆฌํ•˜๋ฉด์„œ ์žˆ์—ˆ๋˜ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…์ด๋‚˜ ์•„์‰ฌ์šด ์ ? ๋“ฑ... ํšŒ๊ณ ๋ฅผ ํ•œ ๋ฒˆ ํ•ด๋ณด๋ ค ํ•œ๋‹ค.

 

 

 

โธ๏ธ ๋“ค์–ด๊ฐ€๊ธฐ ์ „

 

๋ณธ๊ฒฉ์ ์œผ๋กœ ํšŒ๊ณ ํ•˜๊ธฐ ์ „์—, ์•ฑ์„ ์‹คํ–‰ํ•˜๋Š” ์˜์ƒ ๊ฐ™์€ ๊ฑธ ํ•œ ๋ฒˆ๋„ ์—…๋กœ๋“œํ•œ ์ ์ด ์—†์–ด์„œ ์•ฑ ์‹คํ–‰ ์˜์ƒ๊ณผ ํ•ด๋‹น ์•ฑ์— ์–ด๋–ค ๊ธฐ๋Šฅ์ด ์žˆ๋Š”์ง€ ์†Œ๊ฐœํ•˜๋ ค ํ•œ๋‹ค.

 

 

์•ฑ ๊ธฐ๋Šฅ ์„ค๋ช…

 

1. ์‚ฌ์šฉ์ž๊ฐ€ ์›”~๊ธˆ์š”์ผ์˜ ์‹๋‹จํ‘œ๋ฅผ ์ž์œ ๋กญ๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์ขŒ์šฐ ์Šคํฌ๋กค ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค.

 

2. ์š”์ผ์— ๋งž๋Š” ์‹๋‹จํ‘œ๋ฅผ ๋ฐ”๋กœ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋„๋ก ๋ฐ”๋กœ ๊ฐ€๊ธฐ ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค๋ฉด, ์˜ค๋Š˜์ด ํ™”์š”์ผ์ด๋ผ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์Šคํฌ๋กคํ•˜์ง€ ์•Š์•„๋„, ์ž๋™์œผ๋กœ ํ™”์š”์ผ ์‹๋‹จํ‘œ๋กœ ๋„˜์–ด๊ฐ€ ๋ณด์—ฌ์ฃผ๋„๋ก ํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

(์ฃผ๋ง์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ์›”์š”์ผ์— ์œ„์น˜ํ•˜๋„๋ก ํ•˜์˜€๋‹ค.)

 

 

iOS ์•ฑ ์‹คํ–‰ ์˜์ƒ & Android ์•ฑ ์‹คํ–‰ ์˜์ƒ

 

์™ผ์ชฝ: iOS ์‹คํ–‰ / ์˜ค๋ฅธ์ชฝ: Android ์‹คํ–‰

 

 

 

 

๐Ÿ–ฅ AWS

 

Amazon S3 : ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์ž๋™ํ™”?

 

์‹๋‹จํ‘œ ์ด๋ฏธ์ง€๋ฅผ ๋ฒ„ํ‚ท์— ์—…๋กœ๋“œํ•˜๋ฉด, ์ž๋™์œผ๋กœ Lambda ํ•จ์ˆ˜์—์„œ ํ•ด๋‹น ์ด๋ฏธ์ง€๋ฅผ ์ฝ์–ด์„œ OCR์„ ์ง„ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.(ํŠธ๋ฆฌ๊ฑฐ)

 

 

์–ด๋А๋ง ๋ฉ”๋‰ด ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฒ„ํ‚ท์— 5์›” ์ฒซ์งธ ์ฃผ ์ด๋ฏธ์ง€๋ถ€ํ„ฐ 6์›” ๋„ท์งธ ์ฃผ ์ด๋ฏธ์ง€๊นŒ์ง€ ์—…๋กœ๋“œ๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค.

 

์ฆ‰, ๋ฒŒ์จ 9์ฃผ์ฐจ๋ฅผ ์˜ฌ๋ฆฐ ๊ฑด๋ฐ ๋งค์ฃผ ์ฃผ๋ง์— ๊นŒ๋จน์ง€ ์•Š๊ณ  ์—…๋กœ๋“œ ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์ง€ ์•Š๊ณ  ์žˆ๋‹ค.

๊พธ์ค€ํžˆ ํ•˜๋Š” ๊ฑธ ์–ด๋ ค์›Œ ํ•˜๋Š” ๋‚ด๊ฐ€, ๊นŒ๋จน์ง€ ์•Š๊ณ  ๋ถ€์ง€๋Ÿฐํžˆ ์ž˜ ์ง„ํ–‰๋˜๊ณ  ์žˆ๋Š” ์ ์€ ๋‹คํ–‰์ธ ๊ฒƒ ๊ฐ™๋‹ค.

 

๊ทธ๋ ‡๋‹ค๋ฉด ์ด๋ ‡๊ฒŒ ๊ณ„์† ์‚ฌ๋žŒ์ด ๋งค์ฃผ ์ผ์ผ์ด ๋„ฃ์–ด ์ฃผ๋Š” ๋ฐฉ๋ฒ• ๋ง๊ณ  ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ ์—†์„๊นŒ?

 

 

"ํฌ๋กค๋ง์„ ํ†ตํ•ด ์ด๋ฏธ์ง€๋ฅผ ๋ฐ›์•„์„œ S3์— ์ €์žฅํ•˜๋Š” ๋ฐฐ์น˜ ํŒŒ์ดํ”„๋ผ์ธ์„ ๋งŒ๋“ค๋ฉด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„ํ…๋ฐ"

 

 

์Œ... ์ƒ๊ฐ๋ณด๋‹ค ์ด ๋ฐฉ๋ฒ•์€ ์ข€ ๊นŒ๋‹ค๋กญ๋‹ค. ๋” ์ •ํ™•ํžˆ ๋งํ•˜๋ฉด ๋‚ด ์„œ๋น„์Šค์— ์ ์šฉํ•˜๊ธฐ ์–ด๋ ต๋‹ค? ์ ์šฉํ•˜๋ ค๋ฉด ์ „์ฒด์ ์ธ ๊ตฌ์กฐ ์ˆ˜์ •์ด ์ผ์–ด๋‚˜์•ผ ํ•œ๋‹ค.

 

์šฐ์„ , ์‹๋‹จํ‘œ ์‚ฌ์ง„ ๊ฐ™์€ ๊ฒฝ์šฐ์—๋Š” '๋ฉ”๊ฐ€์Šคํ„ฐ๋”” ๊ตฌ๋‚ด์‹๋‹น ๋ฉ”๋‰ดํ‘œ' ์นดํ…Œ๊ณ ๋ฆฌ์— ๋งค์ฃผ ํ•œ ๋ฒˆ์”ฉ ์—…๋ฐ์ดํŠธ ๋œ๋‹ค.

 

 

ํ•ญ์ƒ ๊ณ ์ •์ ์ธ url์— ์—…๋กœ๋“œ๊ฐ€ ๋˜๋ฏ€๋กœ, ํ•ด๋‹น ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์€ ์–ด๋ ต์ง€ ์•Š๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋ฌธ์ œ๋Š” ์˜ค๋ฅธ์ชฝ ์‚ฌ์ง„์ฒ˜๋Ÿผ ์ด๋ฏธ์ง€์˜ ํฌ๊ธฐ๋‚˜ ์œ„์น˜๊ฐ€ ํ•ญ์ƒ ๋ฐ”๋€๋‹ค๋Š” ์ ์ด๋‹ค.

 

 

ํฌ๋กค๋ง์„ ํ†ตํ•ด ํ•ด๋‹น ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์™€์„œ S3์— ์ ์žฌํ•˜๋„๋ก ํ•  ์ˆ˜๋Š” ์žˆ์ง€๋งŒ, ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋ฌธ์ œ๋กœ ์ธํ•ด OCR ์ธ์‹์—์„œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด๋‹ค.

 

ํ˜„์žฌ OCR ์ƒ˜ํ”Œ ์ธ์‹ ํ˜•ํƒœ๊ฐ€ ์ด๋Ÿฐ ์‹์ธ๋ฐ, ๋‚ด๊ฐ€ ๋“ฑ๋กํ•œ ์ƒ˜ํ”Œ ์ด๋ฏธ์ง€๊ฐ€ ์ ์‹ฌ ๋ฉ”๋‰ด๋งŒ ์ ํžŒ ์ˆ˜์ •ํ•œ ์ด๋ฏธ์ง€์ด๋ฉด์„œ, ์ธ์‹ํ•  ์˜์—ญ์„ ์ง์ ‘ ๋„ฃ์–ด์ค€ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฏธ์ง€์˜ ํฌ๊ธฐ์— ์˜ํ–ฅ์„ ๋งŽ์ด ๋ฐ›๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

 

 

๊ทธ๋ฆฌ๊ณ  ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ ์—ญํ• ์„ ํ•˜๋Š” airflow ๊ณต๋ถ€๊ฐ€ ์•„์ง ๋ถ€์กฑํ•˜๊ธฐ๋„ ํ•˜๊ณ , ์ •๊ธฐ์ ์œผ๋กœ airflow๋ฅผ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ํ™˜๊ฒฝ์˜ ๋ถ€์žฌ?

 

๋ณตํ•ฉ์ ์ธ ์š”์ธ๋“ค์— ์–ฝํ˜€์žˆ๊ณ , ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ์˜€๊ธฐ์— ์ด๋Ÿฌํ•œ ๋ถ€๋ถ„์€ ์ ์šฉํ•˜์ง€ ๋ชปํ•œ๊ฒŒ ์•„์‰ฝ๋‹ค.

(ํ•˜๋ ค๋ฉด ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์€๋ฐ ์šฐ์„  ์ˆœ์œ„ ๊ฐœ๋ฐœ์— ๋ฐ€๋ฆฌ๊ธฐ๋„ ํ•˜๊ณ , ์ œ๋Œ€๋กœ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์ฒœ์ฒœํžˆ ํ•˜๊ณ  ์‹ถ์–ด์„œ ์•„๋งˆ ์ถ”ํ›„์— ๊ฐœ์„ ํ•˜๊ฒŒ ๋  ๋ถ€๋ถ„์ผ ๊ฒƒ ๊ฐ™๋‹ค.)

 

 

 

 

AWS Lambda : DB ์ฝ๊ธฐ ๋ฐ ์“ฐ๊ธฐ ์ž๋™ํ™”?

 

๋งค์ฃผ ์ด๋ฏธ์ง€๋ฅผ S3์—์„œ ํŠน์ • ํŒŒ์ผ์„ ์ฝ์–ด์˜ค๊ธฐ ์œ„ํ•ด, ํŒŒ์ผ ์ด๋ฆ„์„ ๋งค๋ฒˆ ์ง์ ‘ ์ˆ˜์ •ํ•ด์ฃผ๊ณ  ์žˆ๋‹ค.

 

 

์•„๋งˆ ์ด ๊ณผ์ •๋„ airflow์—์„œ ํŒŒ์ผ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•ด์ฃผ๋Š” ํ•จ์ˆ˜ ํ•˜๋‚˜, ๋‚ ์งœ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•ด์ฃผ๋Š” ํ•จ์ˆ˜ ํ•˜๋‚˜๋ฅผ ๊ฐ๊ฐ ๋งŒ๋“ค์–ด์„œ ์ž๋™ํ™”ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.

 

 

 

 

AWS Lambda : DB ์“ฐ๊ธฐ ๋ฐ˜๋ณต ๋ฌธ์ œ

 

์ €๋ฒˆ์—๋„ ์ด ํ˜„์ƒ์ด ๋ฐœ์ƒํ•ด์„œ Lambda ํ•จ์ˆ˜๋ฅผ ์ˆ˜์ •ํ•ด์ฃผ์—ˆ๋Š”๋ฐ, ๊ทธ ๋•Œ ์ž‘์„ฑํ•œ ๋กœ์ง์ด ์ž˜๋ชป๋˜์—ˆ์Œ์„ ๊นจ๋‹ฌ์•˜๋‹ค.

 

 ### ์ด์ „ ์ƒ๋žต ###
 
        try:
            r = table.get_item(
                Key={
                    'Period': {'S': period}
                }
            )
                
            # ์ด๋ฏธ ํ•ด๋‹น ํ‚ค ๊ฐ’ ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ, Lambda ํ•จ์ˆ˜ ์ข…๋ฃŒ
            if 'Item' in r:
                return {
                    'statusCode': 200,
                    'body': '์ด๋ฏธ Key๊ฐ€ ์กด์žฌํ•˜์—ฌ Lambda ํ•จ์ˆ˜๋ฅผ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.'
            }
        
        except:
        	# dynamoDB ํ…Œ์ด๋ธ”์— ์ƒˆ๋กœ ๋ฐ์ดํ„ฐ ์ €์žฅํ•˜๋Š” ๋กœ์ง

### ์ดํ•˜ ์ƒ๋žต ###

 

์œ„์—๊ฐ€ ์ด์ „ ์ฝ”๋“œ์ธ๋ฐ, table์—์„œ ํ‚ค๊ฐ€ 'Period' ์ด๋ฉด์„œ period ์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’๋“ค์„ ๊ฐ€์ ธ์˜ค๋„๋ก(=r) ๋˜์–ด์žˆ๋‹ค.

 

์ด์ƒํ•˜๊ฒŒ ํ•ด๋‹น ๋กœ์ง์—์„œ ๊ณ„์† except๋กœ ๊ฐ€์„œ ๊ณ„์† DB์— ๋ฐ์ดํ„ฐ๊ฐ€ ์Œ“์ด๊ฒŒ๋” ๋™์ž‘๋˜๊ณ  ์žˆ์—ˆ๋‹ค.

get_item ๋ฉ”์„œ๋“œ์—์„œ ์ž๊พธ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ด๋ผ ํŒ๋‹จํ–ˆ๋‹ค.

 

์ฐพ์•„๋ณด๋‹ˆ ์—ฌ๊ธฐ์„œ Key์— ํŒŒํ‹ฐ์…˜ ํ‚ค ๋ฟ ๋งŒ ์•„๋‹ˆ๋ผ, ์ •๋ ฌ ํ‚ค๋„ ๋„ฃ์–ด์ค˜์•ผ ํ•ด๊ฒฐ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

 

๊ทธ๋Ÿฌ๋‚˜ ๋‚ด๊ฐ€ ์˜๋„ํ•œ ๋กœ์ง๊ณผ๋Š” ๋‹ฌ๋ผ์„œ, ํŒŒํ‹ฐ์…˜ ํ‚ค๊ฐ’๋งŒ ์ฐพ๋Š” ๋ฉ”์„œ๋“œ๋กœ ์ˆ˜์ •ํ•ด ๋กœ์ง์„ ๋‹ค์‹œ ์ž‘์„ฑํ–ˆ๋‹ค.

 

### ์ด์ „ ์ƒ๋žต ###

	partition_key_name = "Period"
        partition_key_value = period
        
        try:
            # ์Šค์บ” ์ž‘์—…์œผ๋กœ ํŒŒํ‹ฐ์…˜ ํ‚ค ๊ฐ’ ํ™•์ธ
            response = table.scan(
                FilterExpression=f"#{partition_key_name} = :value",
                ExpressionAttributeNames={f"#{partition_key_name}": partition_key_name},
                ExpressionAttributeValues={
                    ":value": partition_key_value
                }
            )
            
            # ํ•ญ๋ชฉ์ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
            items = response['Items']
            if len(items) > 0:
                print(f"ํŒŒํ‹ฐ์…˜ ํ‚ค ๊ฐ’ '{partition_key_value}'์„(๋ฅผ) ๊ฐ€์ง„ ํ•ญ๋ชฉ์ด ํ…Œ์ด๋ธ”์— ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.")
            
            else:
                print(f"ํŒŒํ‹ฐ์…˜ ํ‚ค ๊ฐ’ '{partition_key_value}'์„(๋ฅผ) ๊ฐ€์ง„ ํ•ญ๋ชฉ์ด ํ…Œ์ด๋ธ”์— ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
                
                idx = 0
                for item in res_data[1:]:
                    table.put_item(
                        # ์š”์ผ๋ช…, ๋ฉ”๋‰ด๋‚ด์šฉ
                        Item={
                            'Period': period,
                            'Menu': re.sub(pattern, r'\1 \2', str(idx) + " " + item['inferText'])
                            
                        }
                    )
                    print(f"Data inserted successfully: {item['inferText']}")
                    idx += 1

        except Exception as e:
            print("์˜ค๋ฅ˜ ๋ฐœ์ƒ:", str(e))

 

ํ…Œ์ด๋ธ” scan ๋ฉ”์„œ๋“œ๋กœ ํ•ด๋‹น ํŒŒํ‹ฐ์…˜ ํ‚ค ๊ฐ’์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•œ๋‹ค๋ฉด, ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ์ด๋ฏธ ์ž˜ ๋“ค์–ด๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ๋„˜์–ด๊ฐ€๊ณ , ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์ฃผ๋Š” ๋กœ์ง์œผ๋กœ ๋ฐ”๊ฟจ๋‹ค.

 

 

 

์ด๋ ‡๊ฒŒ ์ ๊ฒ€ํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ–ˆ๋˜ ์ด์œ ๋Š”, DynamoDB์— ๋“ค์–ด๊ฐ€๋Š” ๋ฐ์ดํ„ฐ๋“ค์€ OCR ์ธ์‹ ๊ฒฐ๊ณผ๊ฐ’์ด ๋ฐ”๋กœ ๋“ค์–ด๊ฐ€๋Š”๋ฐ, ์ด๋•Œ ๊ฐ€๋” ์ข…์ข… ์ธ์‹์„ ๋ชปํ•˜๋Š” ํ•œ์ž ๊ฐ™์€ ๊ฒฝ์šฐ์—๋Š” ์ง์ ‘ ์ˆ˜์ •ํ•ด์„œ ๋„ฃ์–ด์ฃผ์–ด์•ผ ํ•˜๊ณ , ๊ทธ๋ฆผ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ด์ƒํ•œ ๋ฌธ์ž๋กœ ์ธ์‹๋˜์–ด ์ง€์›Œ์ค˜์•ผ ํ–ˆ๋‹ค.

 

ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•ด์ฃผ๋ฉด, ์•„๊นŒ ๊ณ ์น˜๊ธฐ์ „ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ณ„์† ์ƒ๊ฒผ๋‹ค. (์ด์ „ Lambda ํ•จ์ˆ˜ ๋กœ์ง์—์„œ ์„ค๋ช…ํ•œ ์ด์œ ๋•Œ๋ฌธ์—)

 

๋กœ์ง์„ ์ œ๋Œ€๋กœ ์ˆ˜์ •ํ•ด์ค€ ๋•๋ถ„์—, DynamoDB์— ๋“ค์–ด๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•ด์ฃผ์–ด๋„ ๋”์ด์ƒ ๋ฐ˜๋ณตํ•ด์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด๊ฐ€์ง€ ์•Š์•˜๋‹ค.

 

 

 

 

๐Ÿ“ฑ Android & iOS

 

๋ฐฑ๊ทธ๋ผ์šด๋“œ ์‹คํ–‰์‹œ ์ž๋™ ์—…๋ฐ์ดํŠธ

Android๋Š” ์•„์ง ํ™•์ธ์„ ๋ชปํ–ˆ๋Š”๋ฐ, iOS ๊ฐ™์€ ๊ฒฝ์šฐ์—๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์‹คํ–‰ํ•ด๋†“๊ณ  ์•ฑ์„ ์ข…๋ฃŒํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฉ”๋‰ด ์—…๋ฐ์ดํŠธ๊ฐ€ ๋˜์ง€ ์•Š๋Š” ํ˜„์ƒ์ด ์žˆ๋‹ค.

์•„๋งˆ ์•ˆ๋“œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ผ ๊ฒƒ ๊ฐ™์€๋ฐ ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ฝ”๋“œ ์ˆ˜์ •์„ ํ•ด์„œ ์•ˆ๋“œ ๋ฐ ios ์•ฑ ๋ฒ„์ „ ์—…๊ทธ๋ ˆ์ด๋“œ๋ฅผ ์‹œ์ผœ์ค˜์•ผํ•  ๊ฒƒ ๊ฐ™๋‹ค.

 

 

iOS

 

๋จผ์ € iOS ๊ฐ™์€ ๊ฒฝ์šฐ,

1. Info.plist ํŒŒ์ผ์— ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—… ํ—ˆ์šฉ์„ ์œ„ํ•œ ์„ค์ •์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š”๋ฐ, UIBackgroundModes ํ‚ค๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  fetch ๊ฐ’์„ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค.

2. ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด AppDelegate ํด๋ž˜์Šค์—์„œ application(_:performFetchWithCompletionHandler:) ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

3. ์•ฑ์—์„œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก, ์•ฑ ๋‚ด์—์„œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๋ ค๋Š” ์ง€์ ์—์„œ UIApplication.shared.setMinimumBackgroundFetchInterval(_:) ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์˜ ์ตœ์†Œ ๊ฐ„๊ฒฉ์„ ์„ค์ •ํ•œ๋‹ค.

 

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์˜ ์ตœ์†Œ ๊ฐ„๊ฒฉ ์„ค์ • (์˜ˆ: 15๋ถ„)
        application.setMinimumBackgroundFetchInterval(900) // 900์ดˆ = 15๋ถ„
        return true
    }

    func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        // ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—… ์ˆ˜ํ–‰ (๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ๋ฐ ์—…๋ฐ์ดํŠธ)
        // completionHandler๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ž‘์—… ์™„๋ฃŒ๋ฅผ ์‹œ์Šคํ…œ์— ์•Œ๋ฆผ
        // ์ž‘์—… ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ .newData, .noData, .failed ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒ
        completionHandler(.newData)
    }
}

 

 

Android

 

์•ˆ๋“œ๋กœ์ด๋“œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€.

1. ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์‹คํ–‰๋  ์„œ๋น„์Šค(๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ)์ธ Service ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›๋Š” ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

2. ์•Œ๋žŒ ๋งค๋‹ˆ์ €๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์„ ์ฃผ๊ธฐ์ ์œผ๋กœ ์‹คํ–‰ํ•˜๋„๋ก ์„ค์ •ํ•œ๋‹ค. AlarmManager ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•Œ๋žŒ์„ ์˜ˆ์•ฝํ•˜๊ณ , PendingIntent๋ฅผ ํ†ตํ•ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

3. ์•ฑ์ด ์‹œ์ž‘๋  ๋•Œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰ํ•˜๋„๋ก ์„ค์ •ํ•œ๋‹ค. onCreate() ๋ฉ”์„œ๋“œ๋‚˜ ๋‹ค๋ฅธ ์ ์ ˆํ•œ ์‹œ์ ์—์„œ startService()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

 

// ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค ์ƒ์„ฑ
public class MyBackgroundService extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—… ์ˆ˜ํ–‰
        // ...

        // ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ์„œ๋น„์Šค ์ข…๋ฃŒ
        stopSelf();
        return START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

// ์•Œ๋žŒ ๋งค๋‹ˆ์ € ์„ค์ •
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, MyBackgroundService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
long intervalMillis = 15 * 60 * 1000; // 15๋ถ„
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), intervalMillis, pendingIntent);

// ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค ์‹คํ–‰
Intent serviceIntent = new Intent(this, MyBackgroundService.class);
startService(serviceIntent);

 

 

๋‚ด๊ฐ€ ๋งŒ๋“  ์„œ๋น„์Šค์— ์ ์šฉํ•˜๋ ค๋ฉด ์‚ฌ์‹ค ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ์ง€ ๊ฐ์ด ์ž˜ ์•ˆ์˜จ๋‹ค. api๋ฅผ ํ†ตํ•ด ์ฃผ๊ธฐ์ ์œผ๋กœ ๋ฐ›์•„์˜ค๊ธฐ๋งŒ ํ•˜๋ฉด ๋ ์ง€? ์•„๋‹ˆ๋ฉด ํ™”๋ฉด ๊ด€๋ จํ•œ ์„ธํŒ…๊นŒ์ง€ ํ•ด์•ผํ• ์ง€...์ง์ ‘ ํ•ด๋ณด๋‹ค๊ฐ€ ๋„ˆ๋ฌด ๋ง‰ํžŒ๋‹ค ์‹ถ์œผ๋ฉด ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์—ฌ์ญค๋ด์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค.

 

 

 

 

๊ฐ€๋กœ๋ชจ๋“œ ์ง€์› X

 

ํ™”๋ฉด์˜ ๊ฐ€๋กœ๋ชจ๋“œ, ์„ธ๋กœ๋ชจ๋“œ๋ฅผ ๋ฏธ์ณ ์ƒ๊ฐํ•˜์ง€ ๋ชปํ–ˆ๋‹ค.

๋„ˆ๋ฌด๋‚˜ ๋‹น์—ฐํ•˜๊ฒŒ ์„ธ๋กœ๋ชจ๋“œ์— ๋งž๊ฒŒ ๊ตฌํ˜„ํ–ˆ๋‹ค.

 

์„ธ๋กœ๋ชจ๋“œ๋งŒ ์ง€์›ํ•˜๋„๋ก ์„ค์ •ํ•˜๊ฑฐ๋‚˜, ๊ฐ€๋กœ๋ชจ๋“œ๊นŒ์ง€ ์ง€์›ํ•˜์—ฌ ๋งŒ๋“ค์—ˆ์–ด์•ผ ํ–ˆ๋Š”๋ฐ ์•ฑ ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ์ด ๋ถ€๋ถ„์€ ๊ทธ๋™์•ˆ ์ „ํ˜€ ๊ณ ๋ คํ•˜์ง€ ๋ชปํ–ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค.

 

 

 

Android

 

์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐ™์€ ๊ฒฝ์šฐ, ์„ธ๋กœ ๊ณ ์ •์„ ํ•ด์ฃผ๋ ค๋ฉด ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

 

1. AndroidManifest.xml ์„ค์ •

android:screenOrientation์— portrait, ๋˜๋Š” landscape๋กœ ์„ค์ •ํ•œ๋‹ค.

<activity
    android:screenOrientation="portrait"></activity>

 

2. Source code ์„ค์ •

SCREEN_ORIENTATION_LANDSCAPE, ํ˜น์€ SCREEN_ORIENTATION_PORRAIT๋กœ ์„ค์ •ํ•œ๋‹ค.

public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
     setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
     setContentView(R.layout.main);
     // ์ดํ•˜ ์ƒ๋žต
}

 

 

iOS

 

iOS๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

 

1. AppDelegate ์„ค์ •

UIInterfaceOrientationMask๋Š” ๋ทฐ ์ปจํŠธ๋กค๋Ÿฌ์˜ ์ง€์›๋˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค ๋ฐฉํ–ฅ์„ ์ง€์ •ํ•˜๋Š” ์ƒ์ˆ˜์ด๋‹ค.

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.portrait
}

 

2. ํ”„๋กœ์ ํŠธ ์„ค์ • ๋ณ€๊ฒฝ

Targets - Info - Supported interface orientations(iPhone)์—์„œ ์ขŒ์šฐ ํšŒ์ „์„ ์‚ญ์ œํ•˜๋„๋ก ํ•œ๋‹ค.

(Xcode์˜ค๋ฅ˜๋กœ ์ธํ•ด ์ด ๋ฐฉ๋ฒ•์œผ๋กœ ์ง„ํ–‰ํ•ด๋„ ์•ˆ๋˜๋Š” ์ด์Šˆ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•˜๋‹ˆ 1๋ฒˆ ๋ฐฉ๋ฒ•์œผ๋กœ ํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.)

 

 

 

 

Splash(Launch) Screen ๋ฌธ์ œ

 

์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐ™์€ ๊ฒฝ์šฐ, ์•„๋ž˜ ์ฒ˜๋Ÿผ ์ด์ค‘ ์Šคํ”Œ๋ž˜์‹œ ํ™”๋ฉด์ด ๋œฌ๋‹ค๊ณ  ํ•˜๋Š”๋ฐ ์•„๋งˆ ๋กœ๋”ฉ ํ™”๋ฉด ์ดํ›„์— ๊ณ„์† ๋นˆ ๋กœ๋”ฉ ํ™”๋ฉด์ด ๋œจ๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์Šคํ”Œ๋ž˜์‹œ ํ™”๋ฉด์ด ๋œฌ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

 

 

์•ˆ๋“œ๋กœ์ด๋“œ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, iOS์—์„œ๋„ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

 

 

 

 

๐Ÿ’ฌ ๋งˆ๋ฌด๋ฆฌ

 

ํ™•์‹คํžˆ ์•ฑ ๊ฐœ๋ฐœ์„ ์ •ํ™•ํ•˜๊ฒŒ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๊ณ  ์ง„ํ–‰ํ•œ ์ , ์„ธ๋ฐ€ํ•œ ๋ถ€๋ถ„์„ ์‹ ๊ฒฝ์“ฐ์ง€ ๋ชปํ–ˆ๋˜ ์ ๋“ค์ด ๋‹ค ๋“œ๋Ÿฌ๋‚œ ๊ฒƒ ๊ฐ™๋‹ค.

 

์ด๋Ÿฐ ๋ถ€๋ถ„์„ ์ œ๋Œ€๋กœ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ๊ฐ€ ์˜ค๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์€๋ฐ...๋„ˆ๋ฌด ์ด๊ฒƒ ์ €๊ฒƒ ๋‹คํ•˜๊ณ  ์‹ถ์–ดํ•˜๋Š” ๋‚˜์˜ ์š•์‹ฌ๋งŒ ๊ฐ€๋“ํ•œ๊ฐ€ ์‹ถ๊ธฐ๋„ ํ•˜๋‹ค.

 

๋” ๋‚˜์€ ์‚ฌ๋žŒ์ด ๋˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๊ณ„์† ๋Š์ž„์—†์ด ํƒ๊ตฌํ•˜๊ณ  ๊ณต๋ถ€ํ•˜๊ณ  ๊ณ ๋ฏผํ•˜๋Š” ์‚ฌ๋žŒ์ด์–ด์•ผ ํ•œ๋‹ค.

 

์‹œ๊ฐ„์  ์—ฌ์œ ๊ฐ€ ์ƒ๊ธฐ๊ฒŒ ๋œ๋‹ค๋ฉด ์•ฑ์„ ์ „์ฒด์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ ํ•˜๊ณ , ์•ฑ ๋ฒ„์ „ ๊ด€๋ฆฌ๋ฅผ ํ•ด์•ผ๊ฒ ๋‹ค!