๐Ÿ“š Today I Learned 15ํšŒ์ฐจ - Flutter ์˜์ƒ ํ†ตํ™” ๐Ÿ“น

2 ๋ถ„ ์†Œ์š”

๐Ÿ“– Flutter ์˜์ƒ ํ†ตํ™” ์•ฑ

๐ŸŽฏ ํ•™์Šต ๋ชฉํ‘œ

์•„๊ณ ๋ผ API๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ 1:1 ์˜์ƒ ํ†ตํ™” ์•ฑ์„ ๊ตฌํ˜„ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๐Ÿ“š ํ•™์Šต ์ˆœ์„œ

โญ ์‚ฌ์ „ ์ง€์‹

  • ์นด๋ฉ”๋ผ ํ”Œ๋Ÿฌ๊ทธ์ธ
  • WebRTC
  • ์—๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ ์นด๋ฉ”๋ผ ์‚ฌ์šฉ
  • ๋‚ด๋น„๊ฒŒ์ด์…˜

๐Ÿ› ๏ธ ์‚ฌ์ „ ์ค€๋น„

  • ์•„๊ณ ๋ผ API
  • ์ด๋ฏธ์ง€์™€ ํฐํŠธ ์ถ”๊ฐ€
  • pubspec yaml ์„ค์ •
  • ๋„ค์ดํ‹ฐ๋ธŒ ์„ค์ •
  • ํ”Œ๋Ÿฌํ„ฐ์—์„œ ๊ถŒํ•œ ๊ด€๋ฆฌ
  • ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐํ™”

๐Ÿ’ป ๊ตฌํ˜„

  • ํ™ˆ ์Šคํฌ๋ฆฐ ์œ„์ ฏ
  • ์Šคํฌ๋ฆฐ ์œ„์ ฏ

๐Ÿ“‹ ํ”„๋กœ์ ํŠธ ๊ตฌ์ƒํ•˜๊ธฐ

์˜์ƒ ํ†ตํ™”๋ฅผ ํ•˜๋ ค๋ฉด ๋™์˜์ƒ๊ณผ ์Œ์„ฑ์„ ์„œ๋กœ ์ „๋‹ฌํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์นด๋ฉ”๋ผ ๊ถŒํ•œ๊ณผ ๋งˆ์ดํฌ ๊ถŒํ•œ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

  • permission_handler ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•ด์„œ ์•ˆ๋“œ๋กœ์ด๋“œ์™€ iOS ๊ถŒํ•œ์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์•Œ์•„๋ณผ ์˜ˆ์ •

๐Ÿ“š ์ฃผ์š” ๋‚ด์šฉ

๐Ÿ“ท ์นด๋ฉ”๋ผ ํ”Œ๋Ÿฌ๊ทธ์ธ

ResolutionPreset ์ •๋ณด

ResolutionPreset ๊ฐ’ ํ•ด์ƒ๋„
ResolutionPreset.low ์•ˆ๋“œ๋กœ์ด๋“œ์™€ ์›น 240p, ์•„์ดํฐ 352x288
ResolutionPreset.medium ์•ˆ๋“œ๋กœ์ด๋“œ์™€ ์›น 480p, ์•„์ดํฐ 640x480
ResolutionPreset.high ์•ˆ๋“œ๋กœ์ด๋“œ์™€ ์›น 720p, ์•„์ดํฐ 1280x720
ResolutionPreset.veryHigh ์•ˆ๋“œ๋กœ์ด๋“œ์™€ ์›น 1080p, ์•„์ดํฐ 1920x1080
ResolutionPreset.ultraHigh ์•ˆ๋“œ๋กœ์ด๋“œ์™€ ์›น 2160p, ์•„์ดํฐ 3840x2160
ResolutionPreset.max ์ตœ๋Œ€ ํ•ด์ƒ๋„

๐ŸŒ WebRTC

์˜์ƒ ํ†ตํ™” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด ์˜์ƒ๊ณผ ์Œ์„ฑ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๊ณ  ์ „์†กํ•˜๊ธฐ, ํด๋ผ์ด์–ธํŠธ ๊ฐ„์˜ ์—ฐ๊ฒฐํ•˜๊ธฐ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์›น ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ฐ˜์œผ๋กœ ํ†ต์‹ ํ•˜๋Š” WebRTC๋ผ๋Š” API๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์Œ์„ฑ ํ†ตํ™”, ์˜์ƒํ†ตํ™”, P2P ํŒŒ์ผ ๊ณต์œ  ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋ฏ€๋กœ WebRTC๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ„๋‹จํžˆ ์˜์ƒ ํ†ตํ™” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ’ก ์‹œ๊ทธ๋„๋ง ์„œ๋ฒ„: WebRTC๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋‘ ํด๋ผ์ด์–ธํŠธ ๋ง๊ณ ๋„ ์ค‘๊ณ„์šฉ ์„œ๋ฒ„๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด ์„œ๋ฒ„๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์•ฑ ๊ฐœ๋ฐœ์— ์ง‘์ค‘ํ•˜๊ณ ์ž ์•„๊ณ ๋ผ ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๊ฐ„์˜ ์ •๋ณด ํ๋ฆ„ ์ ˆ์ฐจ

WebRTC ๋™์ž‘ ์›๋ฆฌ

  1. WebRTC๋ฅผ ์‚ฌ์šฉํ•  ํด๋ผ์ด์–ธํŠธ๋“ค์€ ์„œ๋กœ์—๊ฒŒ ์—ฐ๊ฒฐํ• ์ˆ˜ ์žˆ๋Š” ๊ณต๊ฐœ IP ๋“ฑ์˜ ์ •๋ณด๋ฅผ ์„œ๋ฒ„์— ์ „์†ก
  2. ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์ƒ๋Œ€์˜ ์—ฐ๊ฒฐ ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ด
  3. ์„œ๋ฒ„์—์„œ ๋ฐ›์•„์˜จ ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‚ด ์˜์ƒ ๋ฐ ์Œ์„ฑ์„ ๊ณต์œ ํ•˜๊ณ  ์ƒ๋Œ€์˜ ์˜์ƒ ๋ฐ ์Œ์„ฑ ์ •๋ณด๋ฅผ ์ˆ˜์‹ 

๐Ÿงญ ๋‚ด๋น„๊ฒŒ์ด์…˜

๋‚ด๋น„๊ฒŒ์ด์…˜์€ ํ”Œ๋Ÿฌํ„ฐ์—์„œ ํ™”๋ฉด์„ ์ด๋™ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.

  • ๋‚ด๋น„๊ฒŒ์ด์…˜์€ ์Šคํƒ(Stack)์ด๋ผ๋Š” ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ ์„ค๊ณ„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ”Œ๋Ÿฌํ„ฐ์—์„œ๋Š” ๋‚ด๋น„๊ฒŒ์ด์…˜ ์Šคํƒ์˜ ๊ฐ€์žฅ ์œ„์— ์œ„์น˜ํ•œ ์œ„์ ฏ์„ ํ™”๋ฉด์œผ๋กœ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

Navigator ํด๋ž˜์Šค์—์„œ ์ œ๊ณตํ•˜๋Š” ํ•จ์ˆ˜

๋ฉ”์„œ๋“œ ์„ค๋ช…
push() ์ƒˆ๋กœ์šด ํ™”๋ฉด์„ ์Šคํƒ์— ์ถ”๊ฐ€
pushReplacement() ํ˜„์žฌ ํ™”๋ฉด์„ ์ƒˆ๋กœ์šด ํ™”๋ฉด์œผ๋กœ ๊ต์ฒด
pushAndRemoveUntil() ํŠน์ • ์กฐ๊ฑด๊นŒ์ง€ ๋ชจ๋“  ํ™”๋ฉด์„ ์ œ๊ฑฐํ•˜๊ณ  ์ƒˆ ํ™”๋ฉด ์ถ”๊ฐ€
pop() ํ˜„์žฌ ํ™”๋ฉด์„ ์Šคํƒ์—์„œ ์ œ๊ฑฐ
maybePop() ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ์—๋งŒ ํ˜„์žฌ ํ™”๋ฉด ์ œ๊ฑฐ
popUntil() ํŠน์ • ์กฐ๊ฑด๊นŒ์ง€ ๊ณ„์† ํ™”๋ฉด ์ œ๊ฑฐ

๐Ÿ” ํ”Œ๋Ÿฌํ„ฐ์—์„œ ๊ถŒํ•œ ๊ด€๋ฆฌ

ํŠน์ • ๊ธฐ๋Šฅ๋“ค, ํŠนํžˆ ๋ณด์•ˆ์— ๋ฏผ๊ฐํ•œ ๊ธฐ๋Šฅ์€ ์‚ฌ์šฉ์ž๊ฐ€ ๊ถŒํ•œ์„ ํ—ˆ๊ฐ€ํ•ด์ค˜์•ผ ์•ฑ์—์„œ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์•ˆ๋“œ๋กœ์ด๋“œ์™€ iOS์—๋Š” ํ—ˆ๊ฐ€๋ฅผ ๋ฐ›์•„์•ผ ํ•˜๋Š” ๊ถŒํ•œ์ด ์žˆ๊ณ  ํ—ˆ๊ฐ€๋ฅผ ๋ฐ›์ง€ ์•Š์•„๋„ ๋˜๋Š” ๊ถŒํ•œ์ด ์žˆ์Šต๋‹ˆ๋‹ค (์˜ˆ: ์ธํ„ฐ๋„ท ๊ถŒํ•œ).

โš ๏ธ ์ฃผ์˜: ์นด๋ฉ”๋ผ์™€ ๋งˆ์ดํฌ ๊ถŒํ•œ์˜ ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ด์šฉ ํ—ˆ๊ฐ€๋ฅผ ๊ผญ ๋ฐ›์•„์•ผ์ง€๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๊ถŒํ•œ๋“ค์€ ๋„ค์ดํ‹ฐ๋ธŒ ์„ค์ •์„ ๋“ฑ๋ก์„ ํ–ˆ๋”๋ผ๋„ ํ”Œ๋Ÿฌํ„ฐ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ๊ถŒํ•œ์ด ํ—ˆ๊ฐ€๋๋Š”์ง€ ํ™•์ธํ•ด ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

permission_handler ํ”Œ๋Ÿฌ๊ทธ์ธ ์‚ฌ์šฉ

permission_handler ํ”Œ๋Ÿฌ๊ทธ์ธ์—์„œ Permission ํด๋ž˜์Šค์— ์กด์žฌํ•˜๋Š” ๊ถŒํ•œ์„ ์„ ํƒํ•œ ํ›„ request() ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๊ถŒํ•œ์„ ์š”์ฒญํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

final permission = await Permission.camera.request();

if (permission == PermissionStatus.granted) {
  // ๊ถŒํ•œ ํ—ˆ๊ฐ€ ์™„๋ฃŒ
} else {
  // ๊ถŒํ•œ ์—†์Œ
}

PermissionStatus ํด๋ž˜์Šค

๊ฐ’ ์„ค๋ช…
denied ๊ถŒํ•œ์ด ๊ฑฐ๋ถ€๋จ
granted ๊ถŒํ•œ์ด ํ—ˆ๊ฐ€๋จ
restricted ๊ถŒํ•œ์ด ์ œํ•œ๋จ (iOS์˜ parental controls ๋“ฑ)
limited ์ œํ•œ์ ์œผ๋กœ ๊ถŒํ•œ์ด ํ—ˆ๊ฐ€๋จ (iOS 14+)
permanentlyDenied ๊ถŒํ•œ์ด ์˜๊ตฌ์ ์œผ๋กœ ๊ฑฐ๋ถ€๋จ (์„ค์ •์—์„œ๋งŒ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ)

์—ฌ๋Ÿฌ ๊ถŒํ•œ ๋™์‹œ์— ์š”์ฒญํ•˜๊ธฐ

๊ถŒํ•œ์„ ์ƒํ™ฉ์— ๋งž๊ฒŒ ํ•˜๋‚˜์”ฉ ์š”์ฒญํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ์ง€๋งŒ, ํ•„์š”ํ•œ ๊ถŒํ•œ์„ ํ•œ ๋ฒˆ์— ์—ฐ์†์ ์œผ๋กœ ์š”์ฒญํ•  ๋•Œ๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์š”์ฒญํ•˜๊ณ  ์‹ถ์€ ๊ถŒํ•œ์„ ์ˆœ์„œ๋Œ€๋กœ List์— ๋„ฃ์–ด์„œ request() ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ด ์ฃผ๋ฉด ์—ฌ๋Ÿฌ ๊ถŒํ•œ์„ ๋‹จ๋ฒˆ์— ์š”์ฒญํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

final resp = await [Permission.camera, Permission.microphone].request();

final cameraPermission = resp[Permission.camera];
final micPermission = resp[Permission.microphone];

๐Ÿ“ ๋งˆ๋ฌด๋ฆฌ

โœ… ์˜ค๋Š˜ ๋ฐฐ์šด ๊ฒƒ

  • ์นด๋ฉ”๋ผ ํ”Œ๋Ÿฌ๊ทธ์ธ: ResolutionPreset์„ ํ†ตํ•œ ํ•ด์ƒ๋„ ์„ค์ •
  • WebRTC: ์‹ค์‹œ๊ฐ„ ํ†ต์‹  ํ”„๋กœํ† ์ฝœ๊ณผ ์‹œ๊ทธ๋„๋ง ์„œ๋ฒ„์˜ ์—ญํ• 
  • ๋‚ด๋น„๊ฒŒ์ด์…˜: ์Šคํƒ ๊ตฌ์กฐ๋ฅผ ์ด์šฉํ•œ ํ™”๋ฉด ์ „ํ™˜ ๊ด€๋ฆฌ
  • ๊ถŒํ•œ ๊ด€๋ฆฌ: permission_handler๋ฅผ ํ†ตํ•œ ์นด๋ฉ”๋ผ/๋งˆ์ดํฌ ๊ถŒํ•œ ์š”์ฒญ
  • PermissionStatus: ๊ถŒํ•œ ์ƒํƒœ ์ข…๋ฅ˜์™€ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•

๐Ÿš€ ๋‹ค์Œ ๊ณ„ํš

  • ์•„๊ณ ๋ผ API ์„ค์ • ๋ฐ ์—ฐ๋™
  • ํ™ˆ ์Šคํฌ๋ฆฐ๊ณผ ํ†ตํ™” ์Šคํฌ๋ฆฐ ๊ตฌํ˜„
  • ์‹ค์ œ ์˜์ƒ ํ†ตํ™” ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ