반응형

맥 원격접속은 파인더(Finder)에서 [Command+K] 로 쉽게 VNC를 실행할 수 있습니다. 이때 사용되는 디폴트 포트는 5900 입니다.

개인적으로 회사컴에 원격접속을 하기 위해서 열린 포트는 윈도우용 원격데스크톱의 포트인 3389 입니다. 그렇다 보니 윈도 접근은 쉬운데, 회사 맥에 원격접속을 하려면 절차가 까다롭습니다. 그래서 맥 VNC서버 포트 자체를 5900에서 3389로 바꾸려고 합니다.

맥 VNC 원격접속 포트를 5900에서 윈도우 원격데스크탑 포트인 3389로 변경하기

$ sudo vi /etc/services

# 5900 포트 검색 후 3389로 변경
/5900

# 기존 3389는 주석 처리
# ms-wbt-server 3389/udp    # MS WBT Server
# ms-wbt-server 3389/tcp    # MS WBT Server

# 5900 포트는 3389로 변경
rfb             3389/tcp    vnc-server # VNC Server
rfb             3389/udp    vnc-server # VNC Server

ARDAgent.app 재실행

sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -restart -agent

3389 포트로 원격 접속 (Finder > [Command+K] 단축키)

원격 접속이 안되는 경우에는 시스템을 리붓 후 연결을 해보세요.

반응형
블로그 이미지

BitSense

뷰파인더로 보는 프로그래머의 세상 페이스북 @bitsense 트위터 @picory 스카이프 picory MSN drawhalf@dreamwiz.com

댓글을 달아 주세요

반응형

갑자기 크롬 확장 앱이 만들어 보고 싶어졌습니다. 몇년 전에 관심을 가지고 잠깐 보기는 했지만, 멀 만들지??? 하는 생각에 잠깐 보고, 이렇게 만드는 구나~~ 하고 말았는데, 유투브 동영상에 나오는 광고가 귀찮아서 없애볼까 하는 생각에 다시 크롭앱을 보기 시작했네요..

크롬 관련된 개발할 수 있는 종류가 몇가지 됩니다. https://developer.chrome.com/docs/

 

Documentation - Chrome Developers

Build the next generation of web experiences.

developer.chrome.com

이중에서 페이지가 로딩되면 곧바로 실행되어야 하니, Extensions 항목을 먼저 공부해 봅니다.

https://developer.chrome.com/docs/extensions/

 

Extensions - Chrome Developers

Extensions are software programs, built on web technologies (such as HTML, CSS, and JavaScript) that enable users to customize the Chrome browsing experience.

developer.chrome.com

크롬앱은 기본 js/ ts 구동이 됩니다. js는 쉽지만, 또 쉽지 않은 언어라, 잠시 훑어 보고 오시는 것도 좋은 방법일 거 같습니다.

소스 보기

잠시 크롬 확장앱 구조를 보겠습니다. (샘플 참조 : https://developer.chrome.com/docs/extensions/mv3/overview/)

- manifest.json
- hello.html
- icon.png

1. manifest.json

해당 파일은 설정 페이지 입니다. 실행시 필요 권한, 백그라운드 콜백 파일 등을 지정합니다. 현재는 v3를 사용하는 것을 권장하고 있습니다.

{
  "name": "Hello Extensions",
  "description": "Base Level Extension",
  "version": "1.0",
  "manifest_version": 3,
  "action": {
    "default_popup": "hello.html",
    "default_icon": "icon.png"
  },
  "commands": {
    "_execute_action": {
      "suggested_key": {
        "default": "Ctrl+Shift+F",
        "mac": "MacCtrl+Shift+F"
      },
      "description": "Opens hello.html"
    }
  }
}

1-1. action : 등록된 아이콘을 클릭할 경우 실행될 팝업창과 아이콘을 지정합니다.

1-2. commands : 바로가기 키를 활성화 하는 명령어 입니다. 해당 키조합을 누를 경우, 실행 됩니다. (선택사항. 없어도 됩니다.)

2. hello.html

<html>
  <body>
    <h1>Hello Extensions</h1>
  </body>
</html>

3. icon.png

아이콘 파일 링크 : https://raw.githubusercontent.com/GoogleChrome/chrome-extensions-samples/main/tutorials/hello-world/hello_extensions.png

크롬 extensions을 웹브라우저에 등록하기

1. 크롬 브라우저 주소표시줄 - chrome://extesions

2. 개발자 모드 선택 > [압축해제된 확장 프로그램을 로드합니다.] 클릭

3. 작업한 소스 폴더 선택

4. 크롬 "확장 브라우저" 아이콘 클릭 > "Hello Extensions" 핀 클릭

5. 크롬 "확장 브라우저" 아이콘 왼쪽 > "Hi" 아이콘 클릭

기본 크롬 Extensions 앱 작업 및 크롬 브라우저 추가 작업은 완료했습니다.

다음은 크롬 Extensions에서 Service Worker로  자동실행하여서 현재 웹페이지의 배경화면을 변경하는 작업을 해보겠습니다.

감사합니다.

반응형
블로그 이미지

BitSense

뷰파인더로 보는 프로그래머의 세상 페이스북 @bitsense 트위터 @picory 스카이프 picory MSN drawhalf@dreamwiz.com

댓글을 달아 주세요

반응형

.gitignore ?

github, gitlab 등으로 소스 관리 및 배포가 대세입니다. 하지만 개발하는 OS, 플랫폼, IDE 등 사용환경에 따라 각자 관리하는, 배포에 상관없는 파일이나 디렉토리가 생깁니다. 이 파일들을 제외하기 위해서 .gitignore 파일이 사용됩니다.

파일 생성

git init

사용 방법

// flutter 프로젝트 기준으로 정리합니다.

// 지정된 파일 제외
.metadata

// 특정 패턴 파일들 제외
*.lock // lock 확장자 파일 제외
.*    // . 으로 시작하는 파일 제외

// 특정 디렉토리만 삭제. 맨앞에 / 붙여야 합니다.
/android/

// 디렉토리 이하 특정 파일 제외
/android/*.lock   // android/ 이하 lock 확장자 파일 들 제외
반응형
블로그 이미지

BitSense

뷰파인더로 보는 프로그래머의 세상 페이스북 @bitsense 트위터 @picory 스카이프 picory MSN drawhalf@dreamwiz.com

댓글을 달아 주세요

반응형

FlutterFire는 Flutter 앱으로 Firebase를 연동하는 Flutter 플러그인 세트 입니다. 기본은 macos 개발을 위한 정보 확인 중에 찾은 자료라서 플랫폼 별로 모두 설정 확인을 하도록 해보겠습니다.

주의) 1주일 가까이 firebase와 씨름을 한 거 같습니다. 상황이 m1 맥미니를 구입한지 얼마 안되었고, flutter 2.0에 깜짝 발표된 뒤라, 먼가 정리되지 않은 상태에서 버전 이슈라고만 생각을 했었는데... ㅠ,.ㅠ

더보기

기본 시스템 환경

Mac Mini 2020 M1 (8core CPU, 8core GPU, 8GB Ram), macOS Big Sur 11.2.2

Flutter 2.0.2 / Dart 2.12.12 / CocoaPods 1.10.1
Android Studio 4.1.2
Xcode 12.4

설치

firebase 사이트는 iOS, android, Web 앱 설정만 있습니다. 저는 Flutter로 데스크탑 앱을 만들고 있는 중이라, 저의 개인적인 요구에 따라서 macOS 연동을 목표로 정리를 합니다. 하지만 iOS와 설정이 거의 동일하기 때문에 되도록 같이 설명을 하겠습니다.

로컬 머신에서 flutter 프로젝트를 생성하고, Firebase Console에 프로젝트 생성 혹은 기존 프로젝트에서 앱 추가를 합니다.

Cloud Firestore 앱 추가

iOS 앱 추가 - macos 와 공통으로 사용해야할 앱

iOS 번들 ID 확인 (혹시 이미 만들어 놓은 프로젝트에서 번들 ID를 모르신다면 참조하세요)

os(macos)/Runner.xcworkspace 프로젝트를 Xcode로 열고, 최상단 Runner 선택 후 General 탭 > Identity 영역 > Bundle Identifier 항목 확인.

Android Studio 에서 프로젝트 생성을 할때, Project Name을 입력한 다음 페이지에 Package name이 번들 ID 입니다. flutter create [project]로 직접 생성했다면, com.example.project가 기본 번들ID로 생성됩니다.

iOS/macOS 설정 및 소스 일부 변경 (Xcode 활용)

구성 파일 다운로드

GoogleService-Info.plist 파일 다운로드 및 Xcode에 추가

Runner 선택 및 오른쪽 버튼 클릭 > Add Files to "Runner" 클릭 > (Copy items if needed 옵션 선택) > GoogleService-Info.plist 선택 추 (* Runner 폴더 밑으로 추가를 해주셔야 합니다)

Firebase Emulator Suite 사용 설정

Firebase Emulator Suite는 빠르고 복잡하지 않은 설정을 지원하기 위해서 암호화 되지 않은 네트워킹 연결을 사용합니다. macOS는 기본으로 암호회된 네트워킹 연결을 요구합니다. 로컬 머신에서 개발하는 동안 Firebase Emulator Suite를 사용하려면, 작업 중인 macOS 앱에 보안이 되지 않는 로컬 네트워크 서비스에 연결하도록 허용해야 합니다.

ios(macos)/Runnder/Info.plist 에 아래 설정을 추가합니다.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsLocalNetworking</key>
    <true/>
</dict>

Deployment Target 변경

iOS 9.0 > 10.0, macOS 10.11 > 10.12

# macos/Podfile
platform :osx, '10.12'

# ios/Podfile
platform :ios, '10.0'

AppDelegate.swift

# 추가 코드
import Firebase

FirebaseApp.configure()
    
# 적용 예
import Cocoa
import FlutterMacOS
import Firebase

@NSApplicationMain
class AppDelegate: FlutterAppDelegate {
  override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
    FirebaseApp.configure()
    return true
  }
}

iOS/ macOS 빌드 시간 개선 (Podfile 변경)

현재 Firebase iOS SDK는 Xcode로 빌드시 5분 이상 걸릴 수 있는 약 500k 줄 짜리 c++ 코드에 의존하고 있습니다. 빌드 시간을 크게 단축하기 위해서, ios/Podfile에 1줄을 추가해 프리컴파일된 버전을 사용하도록 합니다.

# ios(macos) /Podfile 추가
pod 'FirebaseFirestore', :git => 'https://github.com/invertase/firestore-ios-sdk-frameworks.git', :tag => '6.26.0'

// 추가 위치
# ...
target 'Runner' do
  pod 'FirebaseFirestore', :git => 'https://github.com/invertase/firestore-ios-sdk-frameworks.git', :tag => $FirebaseSDKVersion
# ...
end

FirebaseSDKVersion 변수는 아래 Native SDK 버전 정의를 참조하세요.

추가로 cocoapods를 1.9.1 이나 그 이상 버전으로 업그레이드 힙니다. gem install cocoapods
(참조 : https://github.com/FirebaseExtended/flutterfire/issues/2751)

저의 경우에는 2021-03-13 현재, 1.10.1로 업그레이드가 되었습니다.

Native SDK 버전 재정의

최상단 platform 정의 바로 밑에 추가해주세요.

# ios(macos)/Podfile

# Override Firebase SDK Version
$FirebaseSDKVersion = '6.33.0'

pod install 실행

실행 테스트

오류 팁

 % flutter run -d macos
Changing current working directory to: /Volumes/Data/Study/flutter/nativeappmaker
Launching lib/main.dart on macOS in debug mode...
Running pod install...                                           1,775ms
In file included from /Users/websniper/Development/flutter/.pub-cache/hosted/pub.dartlang.org/cloud_firestore-0.16.0+1/macos/Classes/FLTFirebaseFirestorePlugin.m:9:
/Users/websniper/Development/flutter/.pub-cache/hosted/pub.dartlang.org/cloud_firestore-0.16.0+1/macos/Classes/Private/FLTFirebaseFirestoreUtils.h:42:4: error: expected a type
+ (FIRFirestoreSource)FIRFirestoreSourceFromArguments:(NSDictionary *_Nonnull)arguments;
   ^                                                                    

FirebaseSDKVersion = '7.4.0'

참조 사이트 : firebase.flutter.dev/docs/overview/

 

 

 

반응형
블로그 이미지

BitSense

뷰파인더로 보는 프로그래머의 세상 페이스북 @bitsense 트위터 @picory 스카이프 picory MSN drawhalf@dreamwiz.com

댓글을 달아 주세요

반응형

하나의 StatefulWidget에서 상태 값을 관리하는 방법은 setState()를 사용하는 것입니다. setState() 없이 상태 값을 관리할 수도 있는데, ValueNotifier를 사용하는 것입니다. ValueNotifier가 좋은 것은 다른 위젯에서 변경한 상태값을 적용할 수 있습니다.

setState() 없이 상태값을 변경하는 예제

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final ValueNotifier<int> _counter = ValueNotifier<int>(0); // ValueNotifier 변수 선언
  final Widget goodJob = const Text('Good job!');
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title)
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('You have pushed the button this many times:'),
            ValueListenableBuilder(
              valueListenable: _counter, // 사용할 변수를 지정. _counter가 변경 되면 자동 호출
              builder: (BuildContext context, int value, Widget? child) {
                // value = _counter 로 적용
                return Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: <Widget>[
                    Text('$value'),
                    child!, // child는 아래 지정된 위젯으로 치환됨
                  ],
                );
              },
              child: goodJob,
            )
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.plus_one),
        onPressed: () => _counter.value += 1, // _counter.value 값이 수정되면 자동 호출
      ),
    );
  }
}

ValueNotifier로 수정한 값을 다른 위젯에서도 사용하고 싶을때

ValueNotifier가 영향을 미치는 범위는 ValueListenableBuilder() 내 입니다. 전체 위젯에 값을 적용하기 위해서는 setState()를 사용해야 하나 그럴 경우 오류가 발생합니다. build가 완료되기 전에 setState()를 호출하게 되면 빨간 화면을 마주하게 됩니다.

이 오류를 피하면서 setState()를 사용하는 방법은 WidgetsBinding.instance.addPostFrameCallback() 입니다.

addPostFrameCallback()는 페이지 빌드 후에 비동기로 콜백함수를 호출하기 때문에 빨간 화면을 피할 수 없습니다.

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final ValueNotifier<int> _counter = ValueNotifier<int>(0); // ValueNotifier 변수 선언
  final Widget goodJob = const Text('Good job!');
  
  int _count = 0;
  
  void setCount(int counter) {
    setState(() {
      _count = counter + 1;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title)
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('You have pushed the button this many times:'),
            ValueListenableBuilder(
              valueListenable: _counter, // 사용할 변수를 지정. _counter가 변경 되면 자동 호출
              builder: (BuildContext context, int value, Widget? child) {
                // setState() 가 있는 함수를 호출
                WidgetsBinding.instance.addPostFrameCallback((_) {
                  setCount(value);
                });
                
                // value = _counter 로 적용
                return Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: <Widget>[
                    Text('$value'),
                    child!, // child는 아래 지정된 위젯으로 치환됨
                  ],
                );
              },
              child: goodJob,
            ),
            Container(
              child: Text('$_count')
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.plus_one),
        onPressed: () => _counter.value += 1, // _counter.value 값이 수정되면 자동 호출
      ),
    );
  }
}
반응형
블로그 이미지

BitSense

뷰파인더로 보는 프로그래머의 세상 페이스북 @bitsense 트위터 @picory 스카이프 picory MSN drawhalf@dreamwiz.com

댓글을 달아 주세요