기본 콘텐츠로 건너뛰기

[상추 키우기] 두 번째 상추...

 게으름으로 인하여 두 번째 상추 재배는 수확까지 끝난 다음에야 포스팅을 하게 되었습니다. 두 번째 상추 재배는 새로운 그로잉스펀지와 재배기에 심을 수 있는 12포트 중에서 4포트만 사용하여 상추를 재배했습니다. 그리고, TDS 측정기를 이용하여 양액의 농도 측정도 하면서 재배를 하였습니다. 수경 재배기를 살 때 포함되어 왔던 그로잉스펀지는 지난번 상추 재배로 인하여 모두 소비되어서 알리에서 새로운 스펀지를 주문했습니다. 주문하면서 실수로 동그란 스펀지가 아닌 네모 스펀지를 주문하는 바람에 포트에 넣었을 때 약간의 공간이 생깁니다만 크게 문제가 되지는 않습니다. 그런데 이번에 스펀지는 번들 스펀지에 비해서 밀도가 높다라고 해야할지 스펀지에 구멍이 적은 것 같습니다. 상추 뿌리가 스펀지를 뚫고 나오는데 지난번 보다 오래 걸린것 같습니다. 다음에 주문할 때에는 이런 부분을 좀 주의해야 할 것 같습니다. 그리고, 스펀지와 함께 TDS 측정기도 함께 구매해서 양액의 농도도 측정하였습니다. 상추의 경우 560 ~ 840 정도의 TDS 범위로 양액을 맞춰주라고 하는데, 수경 재배기에 번들된 양액을 12포트 분량으로 혼합하면 이 범위를 만족합니다. 지난번 재배에서는 이 값을 몰라서 싹을 틔우는 시기와 어린 시기에 양액 농도를 낮게 했었는데 그럴 필요는 없었던 것 같습니다. 약 5주 가량 길러서 수확하기 직전의 상태입니다. 12포트를 키울 떄 보다 빛을 잘 받아서 그런지 웃자람도 없고, 상치 잎의 크기도 지난번보다 상대적으로 컸습니다. 보통 상추를 키울때, 잎이 커지면 일부를 따 먹으면서 계속 키우는데 4포트만 키우게 되면 잎을 따 먹기에는 양이 너무 적어서 다 키워서 한번에 수확을 해야 했습니다. 그래서 다음 재배는 포트수를 조금 더 늘려서 시도해보겠습니다. 

Admob UMP(Google User Messaging Platform) SDK를 이용한 GDPR(General Data Protection Regulation) 대응

얼마 전 부터 운영중인 앱의 Admob 계정을 들어가면 화면 상단에 아래와 같은 눈에 거슬리는 공지가 표시되기 시작했습니다. "올해 안에 EEA 및 영국 사용자에게 광고를 게재하는 모든 게시자는 Google에서 인증한 동의 관리 플랫폼(CMP)을 사용해야 합니다. Google의 자체 동의 관리 솔루션을 포함하여 Google에서 인증한 CMP 이면 어떤 것이든 이 목적으로 사용할 수 있습니다. Google의 동의 관리 솔루션을 사용하는 데 관심이 있으면 먼저 GDPR 메시지를 설정하고 UMP SDK를 구현하세요." 유럽쪽 사용자에 대해서 GDPR(General Data Protection Regulation) 동의 를 받을 수 있도록 하라는 것이다. GDPR 동의에 대해서 처리해야할 법적인 절차를 잘 모르니 친절한(?) Google의 도움을 받을 수 있다고 하니 받는 것으로 했습니다. 메시지를 보면 구글에서 인증한 동의 관리 플랫폼(CMP)를 사용하거나, 구글에서 제공하는 UMP SDK를 이용해서 구현 하면 된다는 내용입니다. 구글에서 UMP SDK를 제공한다고 하니, 이용하기로 합니다. UMP SDK 는 별도의 SDK 형태로 배포되지 않고, Admob SDK에 포함되어 있고, UMP SDK를 이용하여 구현하는 것은 가이드 페이지에 있는 것을 따라가면 되는 수준이라 여기에서는 생략하도록 합니다. # 참고 : - https://support.google.com/admob/answer/10113207 - https://developers.google.com/admob/ios/privacy - https://developers.google.com/admob/android/privacy - https://developers.google.com/admob/flutter/eu-consent 저의 경우에는 구현은 어렵지 않게 했으나, 이 것의 동작을 이해하는데 오랜 시간이 필요했습니다. 그 이유는 사용자로부터 개인정보 이용에 대한 동의를 얻지 못했을 때 광...

Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:393))

현재 flutter로 개발 중인 프로젝트에서 REST API 통신을 하는데, 안드로이드 단말에서 CERTIFICATE_VERIFY_FAILED 오류가 발생하면서 서버와 통신이 이뤄지지 않는 문제가 발생하였습니다. 현재 상황은 apache 서버에 php를 이용하여 api를 만들었고, 운영서버에는 SSL 이 적용되어 있습니다. SSL 인증서는 공인 인증 기관으로 부터 발급된 인증서를 사용하고 있습니다. iOS에서는 문제없이 서버와 통신이 이뤄지지만 안드로이드에서는 오류가 발생합니다. CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate "CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate"로 검색을 하면 공인 기관에서 발급하지 않고 자체적으로 인증서를 발급받아서 사용하는 경우에 문제 해결 방법들이 검색됩니다. 앱 내부에서만 사용하는 서버인 경우에 자체 발급된 인증서를 많이 쓰는 모양입니다.  자체 인증서로 인한 문제를 해결하는 방법은 두가지 정도가 있는 듯 합니다.  1. 인증서 검증을 하지 않는 방법 Dio dio = new Dio(); (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) { client.badCertificateCallback = (X509Certificate cert, String host, int port) = true; return client; }; 2. 인증서를 내장하는 방법 ByteData data = await rootBundle.load('assets/raw/certificate.pem'); SecurityContext context = SecurityContext.defaultConte...

zip4j 2.11.2 버전 호한성 이슈

 암호가 걸린 폴더 단위 압축 파일을 생성하는 기능이 필요하여, 안드로이드에서는 zip4j, iOS에서는 SSZipArchive 라이브러리를 사용하게 되었습니다.  api 레벨에서 zip 압축을 지원하기도 하는데, 폴더 단위 압축과 암호 설정이라는 조건을 더하면 구현도 복잡하고, 압축 파일에 대해서 잘 모르기 때문에 오픈소스의 힘을 빌리게 되었습니다. 그런데 오픈 소스 라이브러리들도 두가지 조건을 지원하는게 별로 없어서 어떤 면에서는 어쩔수 없이 두개 라이브러리를 선택했다고 보시면 됩니다. 물론 두개 라이브러리가 사용자도 많고, 프로젝트도 상대적으로 활성화되어 있는 상태입니다. NoSuchMethodError zip4j와 SSZipArchive를 이용하셔 개발은 순조롭게 진행이 되었습니다만, 테스트 과정에서 안드로이드 api 26 미만에서 아래와 같은 오류가 발생함이 확인되었습니다. ava.lang.NoSuchMethodError: No virtual method toPath()Ljava/nio/file/Path; in class Ljava/io/File; or its super classes (declaration of 'java.io.File' appears in /system/framework/core-libart.jar) at net.lingala.zip4j.util.FileUtils.getRelativeFileName(FileUtils.java:225) at net.lingala.zip4j.tasks.AbstractAddFileToZipTask.cloneAndAdjustZipParameters(AbstractAddFileToZipTask.java:218) at net.lingala.zip4j.tasks.AbstractAddFileToZipTask.addFilesToZip(AbstractAddFileToZipTask.java:71) at net.lingala.zip4j.tasks.AddFolderToZi...

flutter 라이브러리 사용하지 않고 iOS native 코드에서 flutter의 assets 접근하기

flutter로 개발중인 앱을 앱스토어 배포를 위해서 준비중에 아래와 같은 오류를 접하게 되었습니다. App Store Connect Operation Error ITMS-90205: Invalid Bundle. The bundle at 'App.app/PlugIns/AppExtension.appex' contains disallowed nested bundles. App Store Connect Operation Error ITMS-90206: Invalid Bundle. The bundle at 'App.app/PlugIns/AppExtension.appex' contains disallowed file 'Frameworks'.   App Extension 모듈이 Frameworks 폴더를 내포하고 있는 경우에 발생하는 오류 입니다. App Extension 모듈에서 내포하고 있는 Frameworks를 살펴보니 Flutter.framework와 App.framework 였습니다. 두 개의 framework을 참조하는 이유는 App Extension의 구현 자체는 swift로 구현되어 있기는 하지만, flutter를 이용해서 구현된 App과 리소스를 공유하는 부분이 있는데 이 리소스가 flutter의 assets에 포함되어 있어서 참조가 발생했습니다. App Extension에서 flutter의 assets에 등록된 파일을 읽기 위해서 아래와 같은 방식으로 구현되었습니다. 참고 : https://docs.flutter.dev/development/ui/assets-and-images#loading-flutter-assets-in-ios let flutterEngine = FlutterEngine(name: "WidgetViewController") flutterEngine.run() let flutterViewCont...

개발자를 확인할 수 없기 때문에 'iproxy'을 열 수 없습니다.

개발자를 확인할 수 없기 때문에 'iproxy'을 열 수 없습니다. 얼마전 iOS 버전 개발을 위해서 macOS / XCode / flutter 버전을 한꺼번에 변경한 일이 있었습니다. 그러는 과정에서  '개발자를 확인할 수 없기 때문에 'iproxy'을 열 수 없습니다.'라는 오류를 접하게 되었습니다. 구글에서 flutter를 배포하면서 애플에서 요구하는 배포 프로세스를 거치지 않다보니 발생하는 문제라고 합니다. flutter 외에 다른 앱에서 발생할 수 있는 문제이기도 하고, 개발환경을 새로 구성해야 하는 상황에서 또 접할 문제라서 기억 차원에서 간략히 메모를 남깁니다. 터미널에서 아래 명령어를 실행해서 macOS의 인증서 검사 절차에서 무시되도록 하면 됩니다. sudo xattr -d com.apple.quarantine /FLUTTER_PATH/bin/cache/artifacts/usbmuxd/iproxy

Android Emulator closed because internal error:

  최근에 안드로이드 버전에 개발에 충실(?)했더니 iOS 개발 환경에 대한 관리를 소홀히 했었는데, iOS 버전 업데이트를 위해서 작업을 시작했더니, XCode, macOS 업데이트 등을 해야만 하는 상황이 다시 찾아왔습니다. XCode, macOS 업데이트를 하고 여러가지 추가적인 작업들을 어찌어찌  해줘서 iOS 개발 환경을 안정화시켰더니, 안드로이드 개발환경에서 애뮬레이터를 종료하면 아래와 같은 오류 리포트가 계속 출력되네요.. Android Emulator closed because internal error: emuglConfig_init: blacklisted=0 has_guest_renderer=1 아마 macOS 업데이트하면서 관련 드라이버들이 변경되면서 발생하는 문제로 보입니다. 해결은 Android Studio -> Preference -> Appearance & Behavior -> System Settings -> Android SDK 에서 SDK Tools 중 Android SDK Platform-Tools 최신 버전으로 업데이트해서 해결했습니다. 오류 내용을 구글에서 검색을 하면 그래픽 드라이버 업데이트, AVD를 코멘드로 실행하면서 -gpu host 옵션 주는 것 등이 있었으나 저에게는 해당사항이 없었습니다. 다음에 OS 업데이트 하면 또 발생할 수 있는 문제라서 그때 어렴풋이 기억이 나도록 흔적을 남깁니다.

Java, Android, Gradle.. 익숙해지지 않는 개발 환경...

 나는 여러 해 동안 iOS/안드로이드 개발을 해오고 있다. iOS/안드로이드 개발하기 이전에는 MFC 기반의 개발을 다년간 했었고, 일로 인해서 VB, ASP, JAVA, JSP 등도 약간씩 하기도 했었습니다. MFC 개발 환경에 익숙했어서 인지, 늙어서 그런지, 게을러서 그런지 안드로이드 개발에서 아직도 적응이 되지 않는 부분이 Gradle 기반으로 하는 빌드 환경 구성 부분은 아직도 익숙해지지 못했습니다. 게을러서이겠지요. 예전에 MFC 기반으로 개발하던 시절에 비해서 안드로이드 개발 환경은 변화가 비교적 자주 발생하고, SDK 버전 변경시, Android Studio 업데이트 시 어쩔 수 없이 뭔가를 해줘야하는 상황이 발생하는데 그때 그때 찾아보고 대응하는 식으로 하다보니 문제를 키우는게 아닌가 싶기도 합니다. 그리고, 현업에서 개발환경에 변화를 줬다가 기대치 않은 문제가 발생하기도 하고, 급히 처리해야 하는 고객 요구 사항을 제때 대응하지 못하는 문제가 발생할 수 있어서, 반드시 업데이트가 필요한 상황이 아니면 개발 환경은 건드리지 않는 것을 철칙으로 삼아오다보니 새로운 개발환경 적응에 늦게 따라갈 수 밖에 없기도 했습니다. 최근에 flutter 기반으로 개발을 하고 있다보니 내 입장에선 좀 더 복잡해진것 같은데, 서론이 너무 길어진것 같으니 본론으로 들어가도록 하겠습니다. 얼마전부터 개발을 하면서 run 명령을 내리면 에러가 한번 발생하고 다시 실행하면 실행이되는 문제가 발생하기 시작했습니다. 예를 들어서 Log.d(TAG, ""); 와 같은 오류가 없는 라인을 추가 했음에도 오류가 한번 발생하고 다시 실행하는 정상 실행되는 이해할 수 없는 문제였습니다. 처음 문제가 발생했던 시점에는 처리해야할 급한 일들이 산재해 있고, flutter는 hot reload라는 기능을 통해서 빌드 없이(?) 바로 수정 사항이 반영되기 때문에 일을 하는데 크게 불편하지 않은 상황이어서 무시하고 진행을 했습니다. 그런데 최근에 flutter 쪽 코드가 ...