Nexacro N WebView for Android

Nexacro N Runtime for Android 버전을 WebView 베이스로 바꾼 버전 입니다. ## Nexacro N Runtime for Android 버전 대비 차이점 - v8, skia, curl 등 네이티브 모듈이 제거 되었습니다. 그리고 현재 까지 구현된 코드에서는 네이티브 코드(c/c++) 하나도 없습니다. - NexacroUpdatorActivity 가 하던 동작을 NexacroAcitivity 로 이동 시킨후 NexacroUpdatorActivity 를 제거하였습니다. - start_android.json 을 파싱 하는 로직을 제외한 초기 로딩은 새롭게 구현하였습니다. - 컨텐츠의 버전 관리를 archiveinfo.xml 대신 Room 을 이용한 DB 로 변경 하였습니다. - archivefiles.js 생성에 필요한 resource.xml 도 Room 을 이용한 DB 로 변경하였습니다. - DeviceAPI 가 별도로 배포될수 있도록 nexacroLib 에서 분리하여 프로젝트를 구성하였습니다. - 일부 DeviceAPI 모듈 및 기존 기능 중 일부(ApkInstall...)에 대해서 리팩토링을 하였습니다. - [Cordova WebView](https://github.com/apache/cordova-android) 엔진 구조를 참고하여 개발하였습니다. ## 개선사항 - 사용자가 만든 SplashView 를 사용할 수 있게 인터페이스를 추가하였습니다. - 앱 설치 후에도 Update Type을 server or update, local 변경이 자유롭게 가능하도록 변경하였습니다. - Cordova 관련 플러그인 인터페이스를 내장시켜 사용성을 개선하였습니다. ## 테스트 환경 `NEXACRO Studio` - 툴 작업은 아직 되어 있지 않습니다. 대신 iOS 로 디플로이한 프로젝트를 수정없이 사용 가능합니다. - 프레임워크로 사용되는 nexacrolib는 [FEATURE/FEATURE_ANDROID_WEBVIEW](https://tfs2.tobesoft.com:9443/tfs/XPLATFORM/WORK800/_git/WORK800) 브랜치에서 개발되고 있습니다. `Android Studio` - Android Studio Electric Eel | 2022.1.1 Patch 1 이상 최신 안드로이드 스튜디오 버전을 권장합니다. ```sh classpath 'com.android.tools.build:gradle:7.4.1' classpath 'com.google.gms:google-services:4.3.15' ``` ## 사양 - 안드로이드 5.0 롤리팝 (API Level 21) 이상 - 안드로이드 13.0 티라미수 (API Level 33) 타겟팅 ## 의존 라이브러리 - firebase 라이브러리를 NRE 대비 최신 버전으로 업그레이드를 하면서 신규 API 에 맞는 인터페이스로 변경하였습니다. ```sh implementation 'com.google.firebase:firebase-core:21.1.1' implementation 'com.google.firebase:firebase-messaging:23.0.8' ``` - 일부 디바이스API에서 C++를 java로 포팅하는 과정중에 okhttp3 라이브러리를 사용하게 되었습니다. ```sh implementation 'com.squareup.okhttp3:okhttp:4.10.0' ``` - XPUSH 를 사용하는 경우 ```sh implementation 'org.slf4j:slf4j-api:1.7.36' ``` - 전체 의존 라이브러리 리스트 ```sh implementation 'androidx.appcompat:appcompat:1.5.1' implementation 'com.google.android.material:material:1.6.1' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation "androidx.room:room-runtime:2.4.3" implementation 'androidx.exifinterface:exifinterface:1.3.4' implementation 'com.google.firebase:firebase-core:21.1.1' implementation 'com.google.firebase:firebase-messaging:23.0.8' implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'org.slf4j:slf4j-api:1.7.36' annotationProcessor "androidx.room:room-compiler:2.4.3" ``` ## 테스트 방법 - Nexacro N Runtime for Android 와 거의 동일한 방법으로 구동합니다. - NexacroActivity 클래스를 상속받은 [MainActivity.java](http://172.10.12.65:22080/nre/Droid-WebView/src/commit/39986984c6528194720724357439532d14f9d456/app/src/main/java/com/example/nexacro/webview/MainActivity.java) 의 onCreate 함수 안에서 deploy 된 주소를 입력합니다. - 서버, 업데이트, 로컬 방식을 지원 합니다. ```sh public class MainActivity extends NexacroActivity { ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 업데이트 or 서버 방식 setProjectURL("http://172.10.12.59:8080/nexacroN/DroidWebviewSample/_ios_/"); setBootstrapURL("http://172.10.12.59:8080/nexacroN/DroidWebviewSample/_ios_/start_ios.json"); // 로컬 방식 (디플로이된 컨텐츠는 assets/archive 폴더에 위치 시킨다) setBootstrapURL("file:///android_asset/archive/start_android.json"); } ... } ``` ## 사용자 Splash View 변경 방법 - SplashView.java 를 상속 받아서 개발합니다. (http://172.10.12.65:22080/nre/Droid-WebView/commit/0893991ef48b4fc7e7ba53f19f2d2eacaa645e2a) - 진행 상황과 메시지를 setMessage, setProgress 이벤트를 통해서 확인 할수 있습니다. ```sh public class MySplashViewExample extends ConstraintLayout implements SplashView { ... @Override public void setMessage(String message) { TextView textView = getRootView().findViewById(R.id.my_message); textView.setText(message); } @Override public void setProgress(int progress) { ProgressBar progressBar = getRootView().findViewById(R.id.my_progressBar); progressBar.setProgress(progress); } } ``` ## 넥사크로 플러그인 개발 - NexacroPlugin을 상속받은 후 필수 함수를 정의하여 개발합니다. ```sh public class Camera extends NexacroPlugin { @Override public void init(JSONObject paramObject) { // JavaScript에서 exec를 호출할때 method 가 constructor 일때 호출됩니다. } @Override public void release(JSONObject paramObject) { // JavaScript에서 exec를 호출할때 method 가 destroy 일때 호출됩니다. } @Override public void execute(String method, JSONObject paramObject) { // JavaScript에서 exec를 호출할때 method 가 constructor, destroy 이외일때 호출됩니다. } } ``` - 결과값 리턴은 아래와 같은 방식으로 개발합니다. ```sh // JavaScript 에서 호출한 함수에 대한 리턴값을 즉시 전달할때 ex) TCPClientSocket { String resultValue = "문자로된 리턴값"; setReturnValue(resultValue); } // JavaScript 에서 호출한 함수에 대한 리턴값을 PluginResult 클래스로 콜백 전달할때 { // PluginResult(String callbackId, String eventName, String parameters) PluginResult result = new PluginResult(objectId, "_onsuccess", "JSON 형식의 문자열"); webView.sendPluginResult(result); // sendPluginResult(PluginResult pluginResult); } // JavaScript 에서 호출한 함수에 대한 리턴값을 문자열로 콜백 전달할때 { String script = "nexacro.Device.keyEvent(4)"; // KEYCODE_BACK webView.sendPluginResult(script); // sendPluginResult(String script); } ``` - 호출한 액티비티로부터 결과를 받아오는 방법 ```sh public class Sample extends NexacroPlugin { // 액티비티 호출 { Intent intent = new Intent(); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); nexacro.startActivityForResult(this, intent, REQUEST_CODE); } // 결과 받기 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK) { // code here } else if (resultCode == Activity.RESULT_CANCELED) { // code here } } } ``` - 권한이 허가 되어 있는지 확인 ```sh PermissionHelper.hasPermission(this, Manifest.permission.CAMERA); // 카메라 접근 권한 확인 ``` - 권한 요청 하기 ```sh public class Sample extends NexacroPlugin { // 권한 요청 { String[] permissions = {}; permissions = new String[]{ Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}; PermissionHelper.requestPermissions(this, ACCESS_CAMERA, permissions); } // 권한 확인 @Override public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException { for (int r : grantResults) { if (r == PackageManager.PERMISSION_DENIED) { // permission error return; } } if (requestCode == ACCESS_CAMERA) { executeCamera(this.method, this.paramObject); } } } ``` ## 코르도바 플러그인 추가 방법 - (개발중인) 코르도바 제네레이터를 사용합니다. - 코르도바 플러그인 모듈이 생성됩니다. - 넥사크로 프로젝트 하위 경로로 필요한 플러그인 소스가 복사되어 배치됩니다. - 넥사크로 프로젝트에 배치된 소스가 앱 프로젝트에 복사됩니다. - 코르도바 제네레이터가 하지 못하는 작업은 plugin.xml 정보를 바탕으로 아래와 같이 직접 수정합니다. 1. 넥사크로 plugin_config.xml 파일에 코르도바 플러그인을 다음과 같이 등록 ```sh plugin.xml ==> plugin_config.xml 코르도바의 config.xml은 넥사크로의 plugin_config.xml 파일과 동일한 역할을 합니다. ``` 2. 앱의 AndroidManifest.xml 에 권한 및 기타 정보 추가 - uses-permission, uses-feature 3. 플러그인의 종류에 따라서 이외의 작업이 있을수 있습니다. 4. 빌드. ## 개발 편의 기능 1. 주소창을 추가하여 폼 이동을 빠르게 할 수 있습니다. 2. 시작 프로젝트를 동적으로 선택할 수 있습니다. ```sh public class MainActivity extends NexacroActivity { boolean dev_ShowAddressBar = true; boolean dev_ShowProjectSelector = true; ... } ```