웹앱, 하이브리드 앱 프레임워크로 앱을 만들 때 항상 문제가 되는 건 Native를 따라갈 수가 없다는 겁니다.
속도야 뭐 그렇다 쳐도, Native UI를 프레임워크에서 모두 지원하지는 않으니까요.
WApplE.js 도 다른 프레임워크들과 마찬가지로 기본적인 UI component들만을 지원하는 단점을 안고 있지만,
플러그인을 사용자가 만들 수 있게 함으로써 단점을 어느 정도 극뽁~ 하고 있습니다.
하지만 막상 만들려고 보면, Sample 하나 없는게 함정...
그래서 삽질하면서 WebView Plugin 만들며 알게 된 점을 공유하려고 합니다.
(iOS도 비슷하겠지만, 그건 만들어보지 못해서...;;)
1. 상속받는 건 $W.View 입니다 ===>
Plugin은 $W.PluginBase를 상속받는 것이 기본이지만, View에 해당하는 Plugin들은 다릅니다.
$W.View를 상속받아야 합니다. PluginManager에 코드를 작성하실 때나, Native code 작성하실 때 기억해두세요.
(안내에 나와 있긴 합니다만, 제가 못 보고 지나쳐서 삽질했던 관계로 써봅니다.)
< Plugin.js >$W.WPluginManager.define( "WebView", null, ["loadUrl"], null, null, null,
< WPWebView.java >
public class WPWebView extends WPView {
...
2. constructor를 '잘' 만들어야 합니다. ===>
Native code를 작성하는 것은 보통 Class 하나를 작성하는 것입니다 - WebView 니까 WPWebView.java
그리고 만든 클래스가 인스턴스화될 때 작성했던 constructor의 코드들이 실행되겠지요.
이런 당연한 소리를 하는 까닭은, 다른 WApplE.js 내장 View들처럼 Plugin으로 만든 View도 동일한 방식으로 js 코드를
작성하고 동작하도록 구현해야 하기 때문입니다.
보통 WApplE.js View를 만들 때 다음과 같이 사용합니다.
i) new $W.View()
ii) new $W.View($W.LayoutType.LinearVertical)
이런 식으로 대부분의 View의 경우는 두 개 이상의 constructor를 사용하여 인스턴스를 생성할 수 있습니다.
따라서, 특별한 경우가 아니라면 두 개 이상의 constructor가 native code에 구현되게 됩니다.
제가 만든 WebView만 해도, 다음과 같이 세 개의 constructor를 작성했습니다.
public WPWebView() {
this(WPLayoutType.Default.ordinal());
}
public WPWebView(WPLayoutType layoutType) {
this(layoutType.ordinal());
}
public WPWebView(Integer layoutType) {
super(layoutType);
_webView = new WebView(ShareData.context);
_webView.setWebViewClient(new WebViewClient()); // WebViewClient 지정
_setTargetView(_webView);
}
첫번째와 두번쨰 constructor를 보시면, 파라미터로 받은 LayoutType을 ordinal이란 method를 사용하여
변환하고 세번째 constructor에 전달하면서 호출하는 것을 보실 수 있습니다.
ordinal() 은 LayoutType을 알맞은 Integer로 변환하기 위한 method입니다. 변환 같은 거 안 해도 parent class인 $W.View에서
알아서 해주기는 합니다만, 알아둬서 나쁠 건 없죠.
그리고 세번째 constructor에서처럼, 한 번은 _setTargetView()라는 메소드를 호출해줘야 됩니다.
그래야 부모가 되는 View에 추가가 되고 정상 동작하더군요. 이거 찾느라고 꽤 헤맸습니다.(나만 그런가???)
_setTargetView()는 protected 속성이지만 이름에 '_'가 붙어 있는데다가 외부에 공개되어있지 않습니다.
이렇게 되어 있는 이유는 알 수 없지만, 수정되거나 설명이 추가되어야 할 것 같습니다.
이 method가 실질적으로 부모 View에 내가 생성한 View를 추가하는 역할을 합니다.
현재로서는 이 두 가지가 빠지면, View Plugin을 제대로 만들 수 없습니다.
그럼, 저와 같은 삽질을 다른 분들은 하시지 않기를 바라며....
< cf. WPWebView.java >
package com.truemobile.wapplejs.plugin;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.truemobile.wapplejs.core.datastructures.ShareData;
import com.truemobile.wapplejs.plugins.WPView;
import com.truemobile.wapplejs.plugins.datastructures.WPLayoutType;
public class WPWebView extends WPView {
private WebView _webView;
public WPWebView() {
this(WPLayoutType.Default.ordinal());
}
public WPWebView(WPLayoutType layoutType) {
this(layoutType.ordinal());
}
public WPWebView(Integer layoutType) {
super(layoutType);
_webView = new WebView(ShareData.context);
//_webView.getSettings().setJavaScriptEnabled(true);
_webView.setWebViewClient(new WebViewClient()); // WebViewClient 지정
_setTargetView(_webView);
}
public void loadUrl(String url) {
_webView.loadUrl(url);
}
}