반응형

https://dart.dev/

 

Dart programming language

Dart is a client-optimized language for fast apps on any platform

dart.dev

 

https://www.dartpad.dev/? 

 

DartPad

 

www.dartpad.dev

 

 

내장 데이터 타입

int, double

num

bool

String

var

dynamic

List

Set

Map

* Dart는 배열이 없다.

* Dart의 모든 것은 객체 이다. int , double등의 기본형도 객체

 

연산자

??= 대상이 null인 경우에만 우변의 값을 할당

~/ 몫을 구함

 

응용연산자

as 타입 강제 형변환

is 객체가 특정 타입이면 true

is! 객체가 특정 타입이면 false

exp1 ?? exp2 - exp1이 null이면 exp2 반환, null이 아니면 exp1 반환

String name = loginAccount ?? 'Guest';

.. - 캐스케이드 연산자

Account userAccount = Account('kim', 6000)
  ..deposit(500)
  ..withdraw(50000);

?. - 객체가 null이 아니면 멤버의 값 반화, null이면 null 반환

Account account = null;
int num = account?.code;

 

기본 자료구조

List

// 초기화
List<int> numbers = [100, 200, 300];
List<int> numbers2 = [0, ...numbers];

// 병합
List<int> numbers3 = numbers + numbers2;

// 요소접근
int first = numbers[0];

// 순회
for ( int each in numbers ){}

Set - 중복값 허용하지 않음

// 초기화
Set<int> numbers = {100, 200, 300};
Set<int> numbers2 = {0, 100, ...numbers};

// 요소접근 - error
// int first = numbers[0];

// 순회
for ( int each in numbers ){}

// 집합
numbers.union(numbers2);
numbers.intersection(numbers2);
numbers.difference(numbers2);

Map

// 초기화
Map<int, String> map = {
 0: 'a',
 50: 'b',
};

  
 // 요소접근
 String? a = map[50];
 
 // update
 map.update(50, (val) => 'c');

 

 

반응형
반응형

목표

android 프로젝트에 포함된 네이티브소스(c++)에서 crypto++라이브러리를 사용

 

 

환경

OS

: Windows 10

 

빌드환경(crypto++)

: MINGW32

 

빌드 툴(crypto++을 사용하는 Project)

: Android Studio 4.1

 

빌드 절차

1. crypto++ 라이브러리를 NDK로 빌드하여 동적라이브러리 생성

( Android Studio를 이용하여 함께 빌드하도록 구성하는 방법도 존재하겠으나, 성공하지 못했고

매번 빌드하는것보다는 미리 빌드해놓고 링크하는 것이 효율적이므로, 별도로 빌드하는 방식을 채택)

 

2. 빌드된 동적라이브러리(.so)파일을 링크하여 사용하도록 android.mk 구성

 

 

여기서 기술하는 내용은 아래의 github 프로젝트를 기반으로 하였으며,

 

noloader/cryptopp-android-mk

Android.mk build files for Crypto++ project . Contribute to noloader/cryptopp-android-mk development by creating an account on GitHub.

github.com

추가로 설정해야 하는 환경변수관련 내용과

Window 에서 빌드 할때만 발생할 것으로 추정되는 문제

그리고, Android Project에서 빌드된 동적라이브러리(libcrypto++.so)를 링크하는 방법을

추가 하였다.

( NDK 빌드를 포함하는 Android Project 경험이 있는 상황을 가정하며

사용되는 툴에 대한 설명이나, NDK 를 사용하는 프로젝트 구성등은 다루지 않는다. )

 

 

1. crypto++ 라이브러리를 NDK로 빌드로 빌드하여 동적라이브러리 생성

1) Crypto++ 소스파일 다운로드

https://github.com/weidai11/cryptopp 프로젝트 소스를 다운로드 받아 압축을 해제한다.

* 이후의 과정은 Shell을 통해 실행한다.

 

2) 빌드 스크립트 복사

(다운받은 압축파일에는 cryptopp 소스과 [TestScripts]내에 crypto++을 빌드 할수 있는 스크립트가 존재한다.

여러 가지 빌드 스크립트 중 cryptest-android-mk.sh 를 사용한다.)

(1) 소스 폴더 내로 이동한 후 다음 명령어를 통해 [TestScripts]폴더의 cryptest-android-mk.sh을 소스파일이 있는 폴더로 복사한다.

cp -p TestScripts/cryptest-android-mk.sh .

 

3) 환경변수 설정

다음의 명령어를 통해 빌드 스크립트를 실행하면 되지만

$bash cryptest-android-mk.sh

아마도 다음과 같은 에러가 발생할 확률이 높다.

ERROR: ANDROID_NDK_ROOT is not a valid path for . Please set it
ANDROID_NDK_ROOTis ''
ERROR: ANDROID_SDK_ROOT is not a valid path for . Please set it
ANDROID_SDK_ROOT is ''

빌드에 필요한 Android ndk와 sdk 경로가 설정되지 않을 경우 발생하는 에러로

 

a. 환경변수를 등록하거나

b. shell 실행파라미터로 설정해주면 되지만

 

설명이 길어지니 cryptest-android-mk.sh 파일을 직접 수정하도록 한다.

cryptest-android-mk.sh 을 편집기로 오픈한 후, 다음과 1행과 2행을 추가해 주면 된다.

ANDROID_NDK_ROOT="/c/Users/xxxx/AppData/Local/Android/Sdk/ndk/20.1.5948944"
ANDROID_SDK_ROOT="/c/Users/xxxx/AppData/Local/Android/Sdk"

# Error checking
if [ ! -d "${ANDROID_NDK_ROOT}" ]; then
    echo "ERROR: ANDROID_NDK_ROOT is not a valid path for ${USER}. Please set it."
    echo "ANDROID_NDK_ROOT is '${ANDROID_NDK_ROOT}'"
    exit 1
fi

# Error checking
if [ ! -d "${ANDROID_SDK_ROOT}" ]; then
    echo "ERROR: ANDROID_SDK_ROOT is not a valid path for ${USER}. Please set it."
    echo "ANDROID_SDK_ROOT is '${ANDROID_SDK_ROOT}'"
    exit 1
fi

 

* 기술해야 하는 경로는 Android Studio의 [File>Project Structure...] 메뉴를 선택 후, SDK Location에서 확인 할 수 있다.

 

4) (아마도 windows에서 발생하는) ndk-build 관련 에러

위의 설정을 마친 후 빌드 커맨드를 실행하면 ndk-build관련 에러가 발생한다.

ERROR: ndk-build is not on-path for . Please set it

cryptest-android-mk.sh 을 편집기로 오픈한 후, ndk-build 라고 기술된 부분을 ndk-build.cmd 로 변경해 준다.

( 총 3군데가 존재한다)

# Error checking
if [ -z "$(command -v ndk-build.cmd 2>/dev/null)"  ]; then
    echo "ERROR: ndk-build is not on-path for ${USER}. Please set it."
    echo "PATH is '${PATH}'"
    exit 1
fi

 

# Clean all past artifacts
ndk-build.cmd APP_ABI=all NDK_PROJECT_PATH="${NDK_PROJECT_PATH}" NDK_APPLICATION_MK="${NDK_APPLICATION_MK}" distclean &>/dev/null

 

if ndk-build.cmd -j "${MAKE_JOBS}" APP_ABI="${platform}" NDK_PROJECT_PATH="${NDK_PROJECT_PATH}" NDK_APPLICATION_MK="${NDK_APPLICATION_MK}" V=1;

(제공되는 빌드 스크립트는 linux를 기준으로 작성되어있고, linux는 ndk-build, windows는 ndk-build.cmd 가 아닌가 추정해 본다)

 

5) 빌드

이제 빌드 스크립트를 실행하여 crypto++라이브러리를 빌드한다.

$bash cryptest-android-mk.sh

정상적이라면 빌드에 사용될 Android.mk와 Application.mk를 다운받은 후, 빌드가 진행된다.

추가로 다운로드 되는 hxx,cxx은 라이브러리 테스트를 위한 소스로 크게 신경쓰지 않아도 된다.

기본적으로 4개의 플랫폼용 라이브러리를 생성하며 문제없이 생성이 완료되면 아래와 같이 표시된다.

빌드시 시간이 꽤 소요되는데, 필요한 플랫폼만 빌드하려면 sh파일의 아래 부분에 필요한 플랫폼만 기술하면 된다.

PLATFORMS=(armeabi-v7a arm64-v8a x86 x86_64)

 

6)라이브러리 확인

빌드를 실행한 폴더의 [libs] 폴더에 각 플랫폼별 바이너리(*.so)가 생성된다.

각각의 폴더 내에는 아래와 같은 4개의 파일이 생성되는데

실제 crypto++ 라이브러리 구동에 필요한 파일은

 

libcryptopp_shared.so 와 

libc++_shared.so 파일이다

(나머지는 라이브러리 테스트를 위한 파일이므로 무시한다)

 

libcryptopp_shared.so 는 crypto++의 구현을 포함하고 있는 라이브러리 이며

libc++_shared.so 는 C++ 표준 라이브러리 이다.

 

libcryptopp_shared.so 이 정상적으로 로드되기 위해서는 libc++_shared.so이 필수적으로 필요한데

이에 대해서는 아래에서 다시 설명한다.

 

2) 빌드된 동적라이브러리(.so)파일을 링크하여 사용하도록 android.mk 구성

1) 폴더 구성

이제 libcryptopp_shared.so를 링크하기 위해 빌드된 libcryptopp_shared.so 파일을 android 프로젝트에 복사해야 한다.

기존의 Native code(c++) 파일들이 [Project Root]/app/src/main/jni]폴더 에 존재하고

crypto++ 관련 headr파일은 [jni/include/cryptopp]에

crypto++ 관련 라이브러리는 [jni/libs/cryptopp]에 위치하도록 구성하는 것을 가정한다.

 

2) 파일 복사

빌드에 사용된 crypto++ 소스중 헤더파일(h)을  [jni/include/cryptopp] 폴더에 복사하고

빌드된 crypto++ 라이브러리를 [jni/libs/cryptopp]에 복사한다.

( 지원하고자 하는 플랫폼(ABI)에 해당하는 폴더를 복사하면 되며, so 파일 중 libcryptopp_shared.so 만 복사한다. 

libc++_shared.so 파일은 Android.mk구성을 통해 NDK의 표준 파일을 사용하도록 구성한다.)

아래와 같은 형태로 구성되면 되겠다.

jni

 - libs

      - cryptopp

           - arm64-v8a / libcryptopp_shared.so                 

           - armeabi-v7a / libcryptopp_shared.so

           - x86 / libcryptopp_shared.so

           - x86_64 / libcryptopp_shared.so

 

3) crypto++ 링크를 위한 Android.mk 구성

이제 기존의 모듈이 crypto++ 파일을 포함하도록 android.mk를 구성하면 된다.

foo.cpp 소스가 crypto++ 라이브러리를 사용한다 가정할때 아래와 같은 구성으로 cryptopp를 링크 할 수 있다.

OCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include/cryptopp
LOCAL_MODULE    := foo
LOCAL_SRC_FILES := foo.cpp
LOCAL_LDLIBS += -llog -ldl
LOCAL_SHARED_LIBRARIES += cryptopp
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_PATH = $(ROOT_PATH)
LOCAL_MODULE := cryptopp
LOCAL_SRC_FILES := $(LOCAL_PATH)/libs/cryptopp/$(TARGET_ARCH_ABI)/libcryptopp_shared.so
LOCAL_SHARED_LIBRARIES += c++_shared
include $(PREBUILT_SHARED_LIBRARY)

 

* 라인별로 추가 설명을 해보자면 대략 다음과 같다.

LOCAL_C_INCLUDES += $(LOCAL_PATH)/include/cryptopp

- crypto++ 헤더 참조를 위해 include 경로를 설정한다.

 

LOCAL_SHARED_LIBRARIES += cryptopp

- foo 모듈에서 cryptopp 라이브러리를 참조함을 표시한다.

 

LOCAL_SRC_FILES := $(LOCAL_PATH)/libs/cryptopp/$(TARGET_ARCH_ABI)/libcryptopp_shared.so

- cryptopp모듈의 소스가 지정된 경로의 에서 libcryptopp_shared.so 파일임을 나타낸다.

- $(LOCAL_PATH)/libs/cryptopp/$(TARGET_ARCH_ABI) 는  [jni/libs/cryptopp] 폴더내의 각 플랫폼별 폴더를 지칭한다.

 

LOCAL_SHARED_LIBRARIES += c++_shared

- cryptopp 모듈이 c++_shared(즉 libc++_shared)를 링크함을 나타낸다.

- libcryptopp_shared.so 시 생성된 libc++_shared.so를 지정하여 기술해도 되지만 이경우 중복참조 warnnig이 발생한다.

- c++_shared 로 지정하여 NDK 기본 라이브러리를 사용하도록 설정한다.(결국은 같은 파일이긴 하다)

 

include $(PREBUILT_SHARED_LIBRARY)

- 이미 빌드된 라이브러리(*.so)를 포함하는 것을 나타낸다.

 

플래폼에 따라 오픈소스를 빌드하는건 항상 시행착오와 시간 투자를 요구하는거 같다. ㅡㅡ^

 

반응형
반응형

Java나 android 프로그램을 개발 할 경우 JNI를 이용하여

native code(c/c++ 등)로 작성된 코드를 빌드하고 호출 할 수 있습니다.

 

WebAssembly를 이용하면 native source 코드를 javascript에서도 호출 가능하도록 빌드 하여 사용 할 수 있습니다.

 

아래의 링크의 내용을 일부 발췌하면 WebAssembly를 다음과 같이 정의 하고 있습니다.

 

웹어셈블리의 컨셉 - 웹어셈블리 | MDN

웹어셈블리의 컨셉 Table of contentsTable of contents 본 글에서는 웹어셈블리의 작동원리 뒤에 숨어있는 컨셉을 설명함과 동시에 웹어셈블리의 목표, 웹어셈블리가 해결할 수 있는 문제, 그리고 웹브

developer.mozilla.org

 

웹어셈블리가 뭔가요?

WebAssembly는 최신 웹 브라우저에서 실행할 수 있는 새로운 유형의 코드이며 새로운 기능과 성능 면에서 큰 이점을 제공합니다. 직접 코드를 작성하는 것이 아니라 C, C ++, RUST 등의 저급 소스 언어를 효과적으로 컴파일하도록 고안되었습니다.

이는 웹 플랫폼에 큰 영향을 미칩니다. 이전에 불가능했던 웹에서 실행되는 클라이언트 응용 프로그램을 사용하여 웹에서 여러 언어로 작성된 코드를 네이티브에 가까운 속도로 실행하는 길을 제공합니다.

게다가 WebAssembly 코드를 사용하여 이를 활용하는 방법을 알 필요조차 없습니다. WebAssembly 모듈을 웹 (또는 Node.js) 앱으로 가져와 JavaScript를 통해 사용할 수 있도록 할 수 있습니다. JavaScript 프레임 워크는 WebAssembly를 사용하여 대규모 성능 이점과 새로운 기능을 제공하면서도 웹 개발자가 쉽게 기능을 사용할 수 있도록 할 수 있습니다.

웹어셈블리의 목표

웹어셈블리는 W3C 웹어셈블리 커뮤니티 그룹에서 다음과 같은 목표들로 만들어지고 있는 열린 표준입니다:

  • 빠르고, 효과적이고, 이식성이 좋을 것 — 웹어셈블리 코드는 일반적인 하드웨어들이 제공하는 기능을 활용하여 여러종류의 플랫폼 위에서 거의 네이티브에 가까운 속도로 실행될 수 있습니다.
  • 읽기 쉽고 디버깅이 가능할 것 — 웹어셈블리는 저수준 어셈블리 언어지만, 손으로 작성하고, 보고, 디버깅할 수는 있도록, 사람이 충분히 읽을 수 있는 수준의 텍스트 포맷을 갖고있습니다 (아직 스펙이 다듬어지는 중이긴 합니다).
  • 안전함을 유지할 것 — 웹어셈블리는 샌드박싱된 실행환경에서 안전하게 돌아갈 수 있도록 설계되었습니다. 웹상의 다른 코드와 마찬가지로, 웹어셈블리 코드도 브라우저의 동일한 출처(same-origin)와 권한정책을 강제할 것입니다.
  • 웹을 망가뜨리지 않을 것 — 웹어셈블리는 다른 웹 기술과 마찰없이 사용되면서 하위호환성을 관리할 수 있도록 설계되었습니다.

 

대략 다음과 같은 컨셉으로 빌드/구동 됩니다.

 

1. 환경설정

2. 빌드

3. 적용

 

순으로 천천히 정리해 보겠습니다.

반응형

'기타' 카테고리의 다른 글

Spring Tool Suite  (0) 2018.09.08
반응형

변수

Type    
val value  like const
var variable  
    var name: String = "tom"
    var age: Int = 18

    var nameVar = "tom"
    var age = 18

함수

fun sum(num1:Int, num2:Int) : Int {
	return num1+num2
}

fun sum1(num1:Int, num2:Int) : Int = num1 + num2

fun sum3(num1:Int, num2:Int) = num1 + num2

fun add10(num1:Int, num2:Int = 10) = num1 + num2

 

클래스

class Person{
    public var name: String = ""
    protected var age: String = ""
    private var phone: String = ""
    internal var address: String = ""
}

Constructor

Primary constructor(주 생성자)

class Person() {
    public var name: String = ""
    protected var age: String = ""
    private var phone: String = ""
    internal var address: String = ""
}


class Person() {
    public var name: String = ""
}

class Person(_name: String) {
    var name: String = _name
}

class Person(var name: String = "") {
}

Secondary constructor(부 생성자)

* 주 생성자 없음

class Person {
    var name: String = ""
    var age: Int  = 18
    
    constructor(_name: String){
        this.name = _name
    }
    
    constructor(_name: String, _age: Int){
        this.name = _name
        this.age = _age
    }
}

* 주 생성자 + 부 생성자 ( 부생성자는 반드시 주생성자를 재호출 해야 한다 --> 주생성자는 반드시 호출 되어야 한다.)

class Person(var _name: String) {
    var name: String = ""
    var age: Int  = 18

    constructor(_name: String, _age: Int) : this(_name){
        this.age = _age
    }
}

* 인자에 대한 디폴트 값을 전달받기 위해 부 생성자를 여러개 만들지 않아도, 디폴트 값을 활용하여 기능을 제공할 수 있다.

class Person(var _name: String, var age: Int = 18, var sex: String = "male" ) 

 

Initializer Block(초기화 블록)

* 초기화 블록은 주 생성자 호출 직후 실행되며, 부 생성자 보다 먼저 실행된다.

* 초기화 블록은 주 생성자가 없더라도, 부 생성자 보다 먼저 실행된다.

class Person{
    var _name: String = ""
    init {
        println("initial block")
    }
}

 

상속

반응형
반응형

native code에서 java class에 접근과 android 난독화(proGuard)

 

// Find the Mat classe
jclass matClass = env->FindClass("org/opencv/core/Mat");

// Get Mat class's methods<getNativeObjAddr()>
jmethodID getNativeObjAddrMethod = env->GetMethodID(matClass, "getNativeObjAddr", "()J");

native code에서 자바 클래스를 액세스 하기위해 java class나 Method를 구하는 경우,

Debug모드에서 잘 동작하던 코드가 Release 모드에서 

JNI DETECTED ERROR IN APPLICATION: JNI NewStringUTF called with pending exception java.lang.NoSuchMethodError: no non=static mathod xxxxxxx

와 같은 에러를 뱉어 내며 Crash나는 현상이 발생할 수 있다.

이러한 에러는 android app 빌드시, 자바 클래스가 난독화 되어 class나 method를 찾지 못하여 발생하는 것으로 보인다.

 

관련 설정은

bundle.gradle(Module: app) 의

buildTypes {
	release {
    	minifyEnabled true 
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 
        }
    }

와 관련된 부분으로

release모드에서만 발생하는 이유는 당연하게도 프로젝트 생성시, release모드에 난독화 활성화 되도록 디폴트로 설정되기 때문이다.

 

release모드에서만 발생하고,

minifyEnabledfalse로 변경했을때 정상적으로 실행된다면 이문제일 확률이 99.9%이다.

 

하지만, 난독화를 아예 비활성 시키기에는 찜찜하니 조그만 더 알아 보자면

난독화는 'proguard-rules.pro'파일에 설정된 내용을 기본으로 반영하므로 해당 파일을 수정해서 특정 Class, method, field등을 난독화 예외 대상으로 지정하면 난독화를 유지한 상태에서 일부 Class만 예외 적용 할 수 있다.

class 전체 예외

-keep class org.opencv.core.Mat { *; }

class 필드 예외

-keep class org.opencv.core.Mat { <fields>; }

class 메소드 예외

-keep class org.opencv.core.Mat { <methods>; }

특정 도메인 이하를 예외하거나 특정 class에서 상속받은 클래스를 예외할 수 있는 방법도 있는 모양이지만,

지금은 귀찮으니 여기까지만 알아본다.

 

*테스트 결과 native코드를 프로젝트에 포함한 경우에는 난독화가 문제가 되지 않았다.

(native코드를 포함한 라이브러리를 다른 프로젝트에서 사용할때 상기의 이슈가 발생함)

 

반응형
반응형

[bundle.gradle]

signingConfigs {
  release {
    keyAlias 'aliasname'
    keyPassword 'password'
    storeFile file('.jks file path')
    storePassword 'password'
  }
}

buildTypes {
  release {
    debuggable true
    signingConfig signingConfigs.release
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  }
}
반응형

+ Recent posts