반응형

플루터(Flutter)는 Dart 로 UI를 개발하기에 무척 편리한 프래임워크이죠.

실제로 플루터가 나오기 전까지 Dart 언어에 대해서 평가가 그리 좋지 않았지만, 플루터 이후에 평가가 완전히 뒤바뀌었죠.

 

제가 플루터로 어플리케이션을 개발하면서 쌓은 노하우중 하나가 어플리케이션 리소스를 enum으로 관리하는 것인데요.

어떤것인지 소개 드리겠습니다.

 

플루터로 UI를 꾸밀때, 기본적으로 필요한 요소들이 있는데요. 이미지, 컬러, 텍스트스타일, 레이아웃 등이 있죠.

이런것들을 관리하기 위해서 개발자 분들은 다양한 방법을 사용하고 있을텐데요.

 

저는 enum을 활용하는 방법을 소개하고자 합니다.

 

어떻게 enum으로 리소스를 관리하지? 라고 궁금증이 생기신 분들이 있을텐데요.

먼저 제가 왜 enum을 선호하는지 부터 알려드리겠습니다.

 

제가 프로그래밍을 하면서 리소스와 관련되서 종종 격었던 문제들이 있었습니다.

- 텍스트로 리소스를 정의하여 사용하는 경우, 오타로 특정 위치에서만 정상적으로 안나오는 상황

- 플리케이션 리소스를 정의하는 방법이 개발자 간에 서로 달라서 중복된 리소스를 사용하는 경우

- 필요 없다고 생각되는 리소스를 삭제해서 리소스가 안나오는 경우

- 혹시 사용되고 있을까봐 삭제하지 못한 리소스

 

주로 요런 문제들인데요. 아마 이런 문제들은 프로그래밍 언어와 상관없이 코딩을 하다보면 종종 격는 문제입니다.

 

Enum으로 리소스를 관리하게 되면 장점은,

- 컴파일시 (또는 editing시)에 에러를 바로 발견 할수 있다.

- 리소스 사용에 대한 검색이 쉽다.

 

단점은

- 리소스를 위해서 enum을 만들어야 하는 번거로움이 있다.

- 자칫 잘못 디자인 되면 사용이 복잡해진다.

 

저는 예전 경험으로 String을 enum으로 관리하여 유사한 문제점들을 줄였던 적이 있었는데, 이를 활용하여 "어떻게 하면 

코딩이 복잡하지 않고 리소스를 사용할 수 있을까?"에 대해서 고민하여 다음과 같은 방식을 만들게 되었습니다.

 

 

첫번째,

Container(child:Image.asset( ResImages.beast.path, width: 120) )

이미지 리소스를 ResImages.beast.path 이렇게 리소스를 사용하는 방법입니다.

위와 같이 사용하기 위해서는 이미지 리소스를 어떻게 정의할지 고민이 필요한데요. 저는 다음과 같은 방식으로 정의합니다.

enum ResImages{

  addDevice("beast.png"),
  battery("people.png"),
  check("dog.png"),
  dashDevLandS("cat.png"),
  dashDevProbeS("fox.png"),
}

현재는 에러가 발생할 것이고, 

이와같이 정의할 수 있게 하기 위해서는 생성자 (constructor)와 추가적인 내용이 필요합니다.

 

enum ResImages{

:

  final String name;
  const ResImages( this.name);
}

이렇게 하면 string을 enum 정의할때 사용 할 수 있게 됩니다.

다음으로 image path를 얻어오는 getter가 있으면 매우 편리해지겠죠?

 

  String get path => "assets/images/$name";

이렇게 enum에 getter를 추가해 줍니다.

 

이렇게 하면 ResImages.beast.path 로 리소스의 위치를 얻어올 수 있게 됩니다.

요즘 coding 환경( ide)가 좋아져서 ResImages. 까지만 치면 정의된 리소스를 모두 볼수 있으니 더더욱 좋죠.

getter는 필요에 따라서 다양하게 추가할 수 있겠죠? 작은 이미지를 따로 모아놔서 smallPath 를 추가한다던가, 에니메이션을 위해서 프래임을 나눠서 준비했다고 한다면 getFrame(int idx) 같은 식으로 말이죠.

 

최종 완성본은 다음과 같습니다.

enum ResImages{

  addDevice("beast.png"),
  battery("people.png"),
  check("dog.png"),
  dashDevLandS("cat.png"),
  dashDevProbeS("fox.png"),
    ;
  final String name;
  const ResImages( this.name);
  String get path => "assets/images/$name";
 
}

 

 

음, 여기서 고민이 되네요.

이미지, 텍스트 스타일, 컬러를 모두 블로그 한 페이지에 정리할지 아니면 나눠서 정리를 할지.....[10분 딜레이]..

스압을 피하기 위해서 나눠서 정리하기로 했습니다. ^^

 

추가로 관심있으시면 아래 링크 참조 부탁드립니다.

 

[1.이미지(Image)] 이미지 관리

[2.컬러(Color)] 색상 관리

[3.텍스트스타일(TextStyle] 텍스트 스타일 관리

 

반응형

RoundedContainer 

모서리가 둥근 container 는 종종 필요합니다.

Container(
            width: 100.0,
            height: 150.0,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.all(Radius.circular(8.0)),
              color: Colors.redAccent,
            ),
            child: [your widget]
)

 

 

RoundedCorners clipping tip.

Rounded container를 만들고 나서 padding 을 없게 꽉 채우게 되는 경우에 corner가  clipping이 안됩니다.

그럴때 ClipRRect를 사용해서 clipping 합니다.

ClipRRect(
  borderRadius: BorderRadius.circular(20), // Image border
  child: SizedBox.fromSize(
    size: Size.fromRadius(48), // Image radius
    child: Image.network('imageUrl', fit: BoxFit.cover),
  ),
)

 

 

https://stackoverflow.com/questions/51513429/how-to-do-rounded-corners-image-in-flutter

 

How to do Rounded Corners Image in Flutter

I am using Flutter to make a list of information about movies. Now I want the cover image on the left to be a rounded corners picture. I did the following, but it didn’t work. Thanks! getItem(...

stackoverflow.com

 

 

 

반응형

Fast API 사용을 위한 서버 구축을 완료 했다면, 이제 서비스 구현을 해 나가야 겠죠?

가장 필요한것은 API들을 만들어 나가는 것인데요.

Web에서 현재 거의 표준이다시피 한 것이 REST API 일 것입니다.

REST API 를 Restfull 하게 설계 하기 위해서는 몇가지 알아 두어야 할 사항이 있습니다.

REST API 설계 레시피

 

1. CRUD - POST/GET/PUT/DELETE 에 맞춰서 설계한다.

2. RESOURE 정의 데이타 중심으로 한다.

 - api에 동사 사용하지 않는다 : http://server.com/get-items => GET http://server.com/items 

 - 소문자만 사용한다 : GET http://server.com/Items => GET http://server.com/items 

 - 단어와 단어 사이에는 "_"(underscore, 밑줄) 대신 "-"(dash, 중간선)을 사용한다. 

  GET http://server.com/shoping_items => GET http://server.com/shoping-items  

 

먼저 HTTP 의 request 종류와 용도를 알아두면 좋습니다.

 

 

HTTP request 와 CRUD

아마 REST API를 검색하면 많은 빈도수로 CRUD가 나올 것입니다.

 

  REST API example  (resource = item)
http://myserver.com/api/item
C
Create
POST
item 생성
POST http://myserver.com/api/item/12223 

  name:"hello",
  value:"1234"
}
R
Read
GET
item 읽기
GET http://myserver.com/api/item/12223 

U
Update
PUT/ PATCH
item 업데이트
PUT http://myserver.com/api/item/12223 

  name:"hello",
  value:"1234"
}
PATCH  http://myserver.com/api/item/12223 

  value:"1234"
}
D
Delete
DELETE
item 삭제
DELETE http://myserver.com/api/item/12223 

 

 

원래 DB 쪽에서 시작된 용어이긴 하지만 일반적인 API 설계시에도 잘 들어 맞습니다.

그래서 REST API 설계시에도 매우 유용한 개념이기 때문에 REST API 설계시 사용하기 시작했습니다.

 

 

 

Fast API로 REST API 설계하기

 

Fast API로 rest api의 형태를 잡기 위해서는 가장 먼저 알아놔야 할것이  rest api 파라미터(parameter)의 형태를 어떻게 가져갈 것인가 입니다.

 

경로 파라미터

url 기본 패스(path)로 정의 하는 형태입니다.

아래와 같이 items 가 api의 resource에 해당하는 파트입니다. 즉, items 에 접근하기 위한 api를 의미합니다. 따로 get-items 와 같이 동사를 붙이지 않죠. GET이라는 행위는 http request의 형식에 GET으로 정의 합니다.

 

GET http://myserver.com/items

 

Fast API로는 아래와 같이 구현 합니다.

from fastapi import FastAPI

app = FastAPI()


@app.get("/items")
async def get_item_counts():
    return {"count": 10}

Fast API로 api를 정의한 부분을 보니 , 간단하고 보기 편하죠?

 

그다음 좀더 확장해서 경로 파라메터에 변수를 포함해서  활용하는 방법입니다. 

패스에 변수를 포함시키는 형태는 이와 같습니다.

GET http://myserver.com/items/{item_id}

ex) GET http://myserver.com/items/10

items/10 은 여기서 10번 item 정보를 가져온다고 가정 하죠.

이를 fast API에서는 아래와 같이 표현합니다.

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id):
    return {"item_id": item_id}

read_item() 이라는 함수에 item_id를 넣고, item_id를 입력받은 변수로 사용하면 됩니다.
실제 구현에서는 item_id에 해당 하는 item을 꺼내서 return 해주면 되겠죠?

 

아래의 user_id 처럼 주소 중간에도 추가가 가능합니다.

@app.get("/users/{user_id}items/{item_id}")
async def read_user_item(user_id, item_id):
    return {
    "user_id": user_id,
    "item_id": item_id
    }

 

형태를 봤을때 경로 파라메터는 아주 단순하죠? 좀더 복잡하고 다양한 형태의 입력을 받아야 하는 경우들이 인터넷 세상에는 많습니다.

 

복잡하고 많은 정보를 입력으로 받아야 하는 경우, 2가지 형태로 구현할 수 있습니다.

첫번째는 쿼리(URL query) 형태입니다.

 

쿼리(Query)

쿼리 형태는 사실 표현 형식에서 경로 형태에 파라메터가 추가되는 형태로 흔히 브라우져에서 주소 입력창에서 자주 보던 형태 일건데요.

아래와 같은 형식입니다.

POST http://myserver.com/items ?user_id="goodboy" & item_id="123"

 

이렇게 ? 뒤에 key-value 형태로 파라메터를 추가해서 전달하는 방식입니다.

python 함수 내에 parameter로 정의 하는 것 만으로도 쿼리 구현이 됩니다. (fast api에 잘 구현되어있어서 편하게 쓸수 있네요.)

@app.post("/items")
async def add_item(user_id:str, item_id:str):
    return {
        "result":"success",
        "item_id":"D1234-889X-XX",
        "price":"5000000",
    }

 

데이타의 형태가 복잡해지거나 로직이 복잡해질 수록 query 처리하기 힘들어 지는 경우들이 발생합니다.

그중 한가지 예로 클래스로 데이타를 묶고 클래스로 데이타를 전달받고 처리하면 편리해질 것입니다.

이때 클래스의 구조가 바뀌면 parameter 형태도 바뀌게 되서 찾아서 수정해야 할 부분도 많아지겠죠.

이런 불편을 덜 수 있는 형태가 Requst body 입니다.

 

Request Body

Requst body를 이용하면 클래스와 같은 데이타 묶음을 처리하기 쉽습니다.

 

코드 를 작성할때 아래와 같이 어떤  정보를 json 으로 다뤄야 할 경우, 다음과 같이 합니다.

fast api에서 이렇게 class 를 json object로 잘 다룰 수 있도록 Pydantic BaseModel 이 구현되어 있습니다.

 

Pydantic BaseModel

먼저 Pydantic모듈의 BaseModel을 import하여 Class를 구성한다.

 

from typing import Union, List, Optional
from fastapi import FastAPI, Query
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


@app.post("/items/{item_id}")
async def add_tree(item:Item):
    pick = itemTable[item]
    return {
        "result":"success",
        "item_name":pick.name,
        "price":pick.price,
    }

이렇게 Item이 모듈화 됨으로 해서 구현이나 관리가 훨씬 편리해지고 유연해 질 수 있습니다.

 

 

이정도를 기초로 익혀두면 자신의 서비스를 확장해 나가는데 도움이 될것 같습니다.

더 심오한 내용이나 복잡한 것들은 추가로 Fast API 사이트를 레퍼런스 삼아서 공부 해야 겠죠 ^^

 

1. NginX 와 Fast API 셋업은 여기를...

 

해피 코딩 ^^!!

 

 

참고자료.

https://juna-dev.tistory.com/7

 

06. Fast API, Request Body (POST, PUT) 받기

지금까지는 GET방식이기에 URL 및 Request Header로 값이 넘어왔다. 하지만 POST방식에서는 Request Body로 넘어오기에 이전가지의 방식으로는 데이터를 받을 수 없다. Request Body는 Pydantic Model을 이용하여

juna-dev.tistory.com

 

Fast API 튜토리얼

https://fastapi.tiangolo.com/ko/tutorial/

 

자습서 - 사용자 안내서 - 도입부 - FastAPI

자습서 - 사용자 안내서 - 도입부 이 자습서는 FastAPI의 대부분의 기능을 단계별로 사용하는 방법을 보여줍니다. 각 섹션은 이전 섹션을 기반해서 점진적으로 만들어 졌지만, 주제에 따라 다르게

fastapi.tiangolo.com

 

'NginX+FastAPI' 카테고리의 다른 글

[NginX+Fast API] 1. Nginx + gunicorn + fast api 설정하기  (0) 2022.11.10
반응형

어플리케이션 개발을 진행하다보면, 서비스 또는 서버가 있으면 더 멋진 프로젝트로 만들 수 있을것 같은 그런 아이디어들이 생길때가 있습니다.

 

하지만 항상 어떻게 만들지 고민들을 하게 되는데, 다행히도 요즘은 여러 블로그와 유투브들에서 다양한 기술들과 방법들을 가이드 하고 있습니다. 

저는 Ubuntu 18.04 에서 Nginx 와 FastAPI 로 셋업을 했습니다.

 

셋업을 위해 필요한 패키지(package)들는 다음과 같습니다.

 

  • python 3.7
  • nginx
  • fastapi
  • uvicorn
  • gunicorn

 

NginX 설정 하기

 

nginx 를 설치를 먼저 합니다.

 

$ sudo apt-get install nginx

NginX가 잘 동작하는지 실행해봅니다.

 

그다음, 이제 nginx 와 app을 연결하는 과정이 필요한데요.

아래와 같이 fast_api.conf 를 nginx 밑에 생성합니다.

$ /etc/nginx/sites-enabled/fast_api.conf

파일이 없을 것이니 아래와 같이 nano 나 기타 editor로 파일을 만듭니다.
$ sudo nano /etc/nginx/sites-enabled/fast_api.conf

 


fast_api.conf 파일을 아래와 같이 수정합니다.

server{
	listen 80;
	server_name 123.45.67.8;  #your public ip
	location / {
#		include proxy_params;
		proxy_pass http://127.0.0.1:8000;
	}
}

그리고 나서 nginx를 제 시작합니다.

$systemctl restart nginx.service

또는

$sudo systemctl restart nginx.service

 

나머지는 pyton pip를 이용해서 설치 해야 하기에 python 설치 이후에 진행합니다.

 

우선 python이 설치 또는 실행 환경이 셋업 되었는지 확인합니다.

 

$ python --version

아마 python 2.7, python 3.6, python 3.7 과 같이 다양한 버전들이 설치 되어있을 것입니다.

주로 python2.x 대 버전은 python 으로 python 3.x 대 버전은 python3 로 실행하게 될건데요.

 

제가 현재 셋업한 환경에서는 python3.7에서 잘 동작을 하는것 같습니다.

 

우분투에 python 이 여러개 설치 되어있다면, configuration 해서 default를 3.7로 해줘야 합니다.

만약 가상환경이나 docker를 사용한다면 이 부분은 고려하지 않아도 됩니다.

저는 ubuntu에 3.7 환경을 설정 하였습니다.

 

$ sudo apt-get install python3.7

$ update-alternatives --install /usr/bin/python python /usr/bin/python3.7 3       <--- 3 은 인덱스로 기존에 설치된것이 있어서 3번째 로 번호를 붙였습니다.

$ update-alternatives --config python
There are 3 choices for the alternative python (providing /usr/bin/python).


  Selection    Path                Priority   Status
------------------------------------------------------------
* 0            /usr/bin/python3.7   3         auto mode
  1            /usr/bin/python2.7   1         manual mode
  2            /usr/bin/python3.6   2         manual mode
  3            /usr/bin/python3.7   3         manual mode

이렇게 python 설치를 하고 나면 pip로 package들을 설치 합니다.

 

$ pip install fastapi
$ pip install uvicorn
$ pip install gunicorn

그리고 아래 sample code를 작성합니다.

~$ mkdir test
~$ nano ~/test/main.py

[main.py]

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def root():
    print("hello")
    return {"message":"Server v0.0-400"}

 

 

자 아래와 같이 테스트를 진행해봅니다.

~$ cd ~/test
~$ uvicorn main:app
INFO:     Started server process [4406]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

이렇게 하면 서버가 동작하는 것을 볼수 있습니다.

browser 에서 http://127.0.0.1:8000 으로 접속을 시도해보면  {"message":"Server v0.0-400"} 이런 결과를 확인 할 수 있습니다.

만약 이상한 것이 나온다면, 뭔가 설정이 잘못된 것이겠죠?

 

 

app을  ubuntu service 등록 하기

app위에서 작성한 앱을 ubuntu(linux)  service 등록 해서 사용합니다.

linux 서비스로 등록 해서 사용하는 이유는 여러가지가 있겠지만,

app을 terminal에서 start 시키고 terminal을 종료 시키면 app 실행이 유지 되지 않는 것도 하나의 이슈이고,

service로 만들어두면 여러가지로 활용이 가능하기 때문입니다.

서버가 부팅되면 자동 실행한다든가 하는 기능을 만들기 쉬워지기도 하죠.

 

ubuntu 에 service daemon을 등록 및 실행하는 과정입니다.

mika 라는 서비스를 만들어 등록하려고 한다고 합시다.


/etc/systemd/system/mika.service    <- 이 위치에 서비스 파일을 만듭니다.

systemctl daemon-reload    <- daemon관리자를 reload해서 새로 만든 서비스 파일을 인식할 수 있도록 합니다.

# systemctl 이라는 명령을 이용하여 서비스를 enable / start/ stop 등의 상태 조절이 가능합니다.

systemctl enable mika  <- 서비스를 enable 합니다.
systemctl start mika  <- 서비스 스타트
systemctl stop mika <- 서비스 종료

 

자 여기까지 하면 nginx 와 fastapi 설정이 완료 되었습니다.

 

앞으로 서비스를 추가 확장을 하려면, REST API를 추가해 나가면 되겠죠?^^

 

2. REST API 설계 는 여기를...

 

그럼.. 해피 코딩!

 

 

 

 

아래는 참고 자료 입니다.

 

NginX + FastAPI

 

https://facerain.club/fastapi-nginx/

 

Nginx로 FastAPI 배포하기 (Feat. Gunicorn)

Nginx와 Gunicorn을 이용하여 FastAPI 서버를 배포하는 방법을 알아봅시다.

facerain.club

 

 

https://velog.io/@ddhyun93/FastAPI-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD-%EC%85%8B%ED%8C%85%EC%9C%BC%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-nginx%EC%99%80-%EC%9B%B9%EC%84%9C%EB%B2%84%EC%9D%98-%EA%B4%80%EA%B3%84

 

 

Nginx - unit. :어플리케이션 서버.

 

https://www.lesstif.com/system-admin/nginx-unit-application-server-118096054.html#nginxunit%EC%B0%A8%EC%84%B8%EB%8C%80applicationserver-application%EC%B6%94%EA%B0%80

 

nginx unit - 차세대 application server

nginx unit은 CentOS 용 ruby 모듈을 제공하지 않습니다.

www.lesstif.com

 

 

Nginx + fast api 셋업 영상

https://youtu.be/SgSnz7kW-Ko

 

'NginX+FastAPI' 카테고리의 다른 글

[NginX+Fast API] 2. REST API 설계  (0) 2022.11.17
반응형

종종 window 11 이나 회사, 학교, 기관에서 사용하는 PC에 추가기능 관련된 기능이 숨겨져 있는 경우가 있습니다.

이때 추가 기능 설치를 해야 하는경우 난감한데요.

 

appwiz.cpl 을 이용하여 추가 기능을 설치 할 수 있습니다.

 

Cmd, Shell, 또는 명령창을 실행합니다.

Window Key + R 을 눌러서 cmd.exe 를 실행하면 됩니다.

(관리자 권한으로 실행해야 하는 경우도 있음)

> appwiz.cpl

 

이렇게 실행하면, 제어판\모든제어판 항목\프로그램 및 기능 이 실행 됩니다.

Windows 기능 켜기/끄기 항목을 선택

그리고 나서, 필요한 기능을 찾아서 설치 하면 됩니다.

 

 

반응형

코딩을 하다보면,  사용자 형식의 데이타 구조를 소팅해서 사용해야 하는 경우가 있습니다.

dart 의 List나 map 같은 자료구조에 보면, sort라는 함수가 있는데요. 

이를 활용하면 쉽게 구할 수 있습니다.

 

가장 기본적인 형태는 다음과 같겠죠.

Data라는 class가 있는데 이를 timestamp 기준으로 sorting이 필요하다고 가정하여 sample code를 작성해봤습니다.

class Data{
  int timestamp; // timestamp 로 
  String s;
  Data(this.timestamp,this.s);
  toString(){
    return "$timestamp:$s";
  }
}

List<Data> datas=[
  Data(1,"heee"),
  Data(4,"yyy"),
  Data(2,"kkk"),
  Data(3,"hhph")
];

comp(Data a, Data b){
  return a.timestamp - b.timestamp;
}

void main() {
  datas.sort((a,b)=> comp(a,b));
  
  
  for(final d in datas){
  print("${d.toString()}");  
  }
  
  
}

 

또,

일반적으로 timestamp를 사용할때 DateTime 을 사용하는 경우가 많은데요.

이런 경우 DateTime의 millisecondsSinceEpoch 을 이용하면 쉽게 처리 할 수 있습니다.

DateTime을 사용하지 않고 millisecondsSinceEpoch로 timestamp를 사용하기도 하죠.

class Data{
  DateTime timestamp; // timestamp 로 
  String s;
  Data(this.timestamp,this.s);
  toString(){
    return "$timestamp:$s";
  }
}



List<Data> datas=[
  Data(DateTime.utc(2022,1,25),"heee"),
  Data(DateTime.utc(2022,2,10),"yyy"),
  Data(DateTime.utc(2022,1,5),"kkk"),
  Data(DateTime.utc(2022,4,1),"hhph")
];

comp(Data a, Data b){
  return a.timestamp.millisecondsSinceEpoch - b.timestamp.millisecondsSinceEpoch;
}

void main() {
  datas.sort((a,b)=> comp(a,b));
  
  
  for(final d in datas){
  print("${d.toString()}");  
  }
  
  
}

 

해피 코딩!!

 

반응형

application 에서 실행중에 사용자가 퍼미션을 허용해야만 동작하는 module들이 있습니다.
이를 위해서 잘 만들어진 어플리케이션들은 퍼미션을 허용하는 UI를 제공하게 됩니다.

flutter에서 기본적인 퍼미션 허용하는 UI를 제공하는 방법을 소개합니다.

permission_handler [https://pub.dev/packages/permission_handler]

flutter에 permission_handler 라는 package가 있는데, 이를 이용하면 매우 쉽게 퍼미션을 설정 할 수 있습니다.


순서
Flutter에서 각 기능에 대한 퍼미션 설정을 위해서는 몇가지 파일들을 수정해야 하는데요.
순서를 한번 따라가 보겠습니다.

1. android manifest 에서 필요한 퍼미션을 추가합니다.
[project] /app/profile/AndroidManifest.xml
파일 안을 살펴보면 아래와 같이 use-permission 부분들이 있습니다.
필요한 퍼미션을 이 파일에 추가합니다.
저는 FINE_LOCATION과 BT 관련 퍼미션이 필요해서 다음과 같이 추가 했습니다.

<uses-permission android:name="android.permission.INTERNET"/>
<!-- 추가한 퍼미션 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>



2. permission_handler를 flutter pub 설정 파일에 추가합니다.
[project]/pubspec.yaml
위 파일에 다음과 같이 추가합니다.
permission_handler의 version은 pub.dev 에서 확인하시면 됩니다.

permission_handler: ^10.2.0

그리고 pub get 하기

3. permission 요청 하기
자 이제 모든 준비가 끝났고, 필요한 시점에 퍼미션 요청을 하면 됩니다.
예를 들면 BT scan전에는 BT 퍼미션이 필요하겠죠? 그러면 BT scan 전에 BT 퍼미션을 요청하는 코드를 작성해서 넣으면 됩니다.
퍼미션을 요청 하는 방법은 사용자 편의성을 고려해서 적용하는게 좋겠죠?
매번 이렇게 필요한 기능을 수행할때 퍼미션을 요청 할 수도 있지만,
사용성을 해치지 않는다면, 앱 최초 실행후 전체 퍼미션을 요청하는 것도 하나의 방법입니다.

더 정교하게 permission 요청 로직을 작성할 수 도 있지만, 아래와 같이 간단한 퍼미션 요청 함수를 만들고,
widget build() 에서 호출해도 어플리케이션 동작에 영향을 주지 않을 겁니다.

아래 사용한 permission의 request() 함수는 이미 퍼미션이 있으면 아무것도 하지 않기 떄문입니다.
또 _permissionCheck() 함수는 async로 만들어 놨기 때문에 build 함수의 퍼포먼스에 영향을 주지 않습니다.
( 영향을 주기야 하겠죠~ ^^ 그러나 무시할 수 있을 만큼이란 의미로 받아들이면 좋겠습니다.)

  _permissionCheck() async{

    print("permission check");

    Map<Permission, PermissionStatus> status = await [
      Permission.locationWhenInUse,
      Permission.bluetooth,
      Permission.bluetoothConnect,
      Permission.bluetoothScan
    ].request();
  }
  
  
class DeviceControlPage extends GetView<DeviceController>{
  const DeviceControlPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    Get.put(DeviceController());
    controller.prepare();

    _permissionCheck();
     :



    return Scaffold(
          resizeToAvoidBottomInset : false,
          body: Obx(()=>Column(
          ....
          );
  }



이상 완료!!!

즐거운 코딩 생황~

반응형

어플리케이션 구성시, named route 를 사용하면, 어플리케이션 구조를 좀더 단순화 할수 있습니다.
그러면 코드의 시인성( readability ) 도 좋아지겠죠?

app route를 사용 하는 방식도 여러가지가 있는데요.
그중에서 저는 아래와 같이 router를 따로 분리해서 사용하는 것을 선호 합니다.


app router의 page 구성


abstract class Routes{

  static const INITIAL = '/';
  static const DEVICE = '/device';
  static const MONITOR = '/monitor';
  static const SEARCH = '/search';
}


class AppPages {
  static final pages = [
    GetPage(
        name: Routes.INITIAL, page: () => const MainPage()),
    GetPage(
        name: Routes.DEVICE, page: () => const DeviceControlPage()),
    GetPage(
        name: Routes.MONITOR, page: () => const MonitorPage()),
    GetPage(
        name: Routes.SEARCH, page: () => const SearchPage()),
  ];
}

+ Recent posts