[Xamarin] Razor Template를 통해 HTML 출력하기

2016. 3. 29. 11:49Mobile

Cross-platform환경에서 복잡한 화면을 HTML을 통해 구성하는 것은 효과적인 방법 중 하나입니다. 특히 이미 작성된 HTML, CSS, Javascript가 있다면 더욱 그럴 것입니다. Xamarin은 개발자가 Razor Template Engin을 통해서 손쉽게 HTML, Javascript, CSS를 제어하고 출력할 수 있습니다. 이 글은 Xamarin iOS, Android를 기준으로 설명을 진행합니다.

Overview

Hybrid App이란 HTML을 통해서 화면을 구성하고 WebView control을 통해서 출력하는 앱을 가리킵니다. 이 경우 앱은 순수 HTML, Javascript로 작성되게 되지만, 화면이 복잡해지고 애니매이션, 흐림, 그림자 등 UI 효과가 추가될 수록 성능적인 한계에 부딪히게 됩니다. 또한 Hybrid App은 Mobile 내부적인 기능에 접근하는 데에도 한계를 가지고 있습니다.

이러한 단점에도 불구하고, HTML로 표현하면 효과적인 부분이 많이 있으며, Xamarin에서는 Razor HTML Template Engin을 활용하여 HTML페이지를 출력하실 수 있고, Platform API는 C#을 통해 제어할 수 있게 제공합니다.

WebView 사용하기

일단 HTML을 출력하기 위해 WebView를 사용하는 방법부터 진행하겠습니다.

iOS

Xamarin.iOS에서는 UIWebView를 통해서 HTML을 출력합니다.

var webView = new UIWebView (View.Bounds);
View.AddSubview(webView);
string contentDirectoryPath = Path.Combine (NSBundle.MainBundle.BundlePath, "Content/");
var html = "<html><h1>Hello</h1><p>World</p></html>";
webView.LoadHtmlString(html, NSBundle.MainBundle.BundleUrl);

UIWebView에 대해 자세한 사항은 다음 링크를 확인하세요 (UIWebView: https://docs.xamarin.com/recipes/ios/content_controls/web_view/)

Android

Xamarin.Adnroid에서는 WebView를 통해서 출력하실 수 있습니다.

// webView is declared in an AXML layout file
var webView = FindViewById<WebView> (Resource.Id.webView);
var html = "<html><h1>Hello</h1><p>World</p></html>";
webView.LoadDataWithBaseURL("file:///android_asset/", html, "text/html", "UTF-8", null);

자세한 사항은 다음 링크를 확인해주세요 (WebView: https://developer.xamarin.com/recipes/android/controls/webview/)

Base Directory 설정하기

HTML내에 포함된 CSS, Javascript, Image 등의 외부리소스를 참조할 수 있도록 BaseDirectory를 제공할 수 있습니다. 예를 들어 다음의 HTML이 있는 경우를 생각해봅시다.

<link rel="stylesheet" href="style.css" />
<img src="image/monkey.jpg" />
<script type="text/javascript" src="jscript.js">

style.css, monkey.jpg, jscript.js는 각 리소스에 대한 상대경로 입니다. 이 상대경로를 제대로 참조할 수 있도록 하기 위해 BaseDictory를 제공하는 것입니다.

iOS

webView.LoadHtmlString (page, NSBundle.MainBundle.BundleUrl);

NSBundle.MainBundle.BundleURL은 Application이 Install된 Directory를 가리키며, 이 경로가 BaseDirectory로 제공되었습니다. HTML에서 참조하는 파일들은 다음과 같이 Resources 폴더에 위치시키면 됩니다.

image

Resources 폴더에 추가된 파일들은 BuildAction을 BundleResource로 변경해주세요.

image

Android

webView.LoadDataWithBaseURL("file:///android_asset/", page, "text/html", "UTF-8", null);

file:///android_asset/는 Android의 Assets폴더를 가리킵니다. 따라서 다음과 같이 파일을 Assets 폴더 하위에 위치시켜 주세요.

image

Build Action도 AndroindAsset로 설정해주세요.

image

HTML, Javascript에서 C#호출하기

HTML에 포함된 링크나 URL은 정상적으로 동작합니다. 예를들어 다음과 같은 링크는 WebView가 Google을 로드하도록 합니다.

<a href="http://google.com/">Google</a>

만약 링크가 상대경로라면 지정한 Base Directory에서 해당 리소스를 찾을 것입니다.

<a href="somepage.html">Local content</a>

Form역시 마찬가지 입니다.

<form method="get" action="http://google.com/"></form>
<form method="get" action="somepage.html"></form>

WebServer를 Xamarin에 포함할 수는 없습니다만, 이에 상응하는 기술을 사용하실 수 있습니다. 예를들어 HTTP GET을 통해 서비스를 호출하고 응답을 Javascript를 통해서 제어하는 등의 작업을 진행하실 수 있습니다. 이러한 작업을 통해 HTML의 데이터를 C#으로 전달하고, C#에서는 응답을 HTML로 출력하실 수 있습니다.

iOS와 Android 모두 C#으로 Navigation event를 가로채어 이에 대한 응답을 진행하실 수 있습니다. 이러한 방식으로 HTML과 webView를 통해서 Hybrid App을 작성하실 수 있습니다.

iOS

iOS의 WebView가 제공하는 ShouldStartLoad event를 override함으로써 Navigation 요청을 통제하실 수 있습니다. 다음과 같이 이벤트 핸들러를 작성하실 수 있습니다.

bool HandleShouldStartLoad (UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navigationType) {
    // return true if handled in code
    // return false to let the web view follow the link 
}

이벤트는 다음과 같이 연결해 줍니다.

webView.ShouldStartLoad += HandleShouldStartLoad;

Android

Android에서는 Sub Class인 WebViewClient를 구현함으로써 Navigation 요청를 통제하실 수 있습니다.

class HybridWebViewClient : WebViewClient {
    public override bool ShouldOverrideUrlLoading (WebView webView, string url) {
        // return true if handled in code
        // return false to let the web view follow the link 
    }
}

그리고 다음과 같이 WebView에 구현한 Class를 전달해 주시면 됩니다.

webView.SetWebViewClient (new HybridWebViewClient ());

Javascript를 C#에서 호출하기

C#을 통해서 Javascript code를 실행할 수 있습니다.

Android

javascript: 접두사와 함께 자바스크립트를 작성 후 webView로 로드하시면 됩니다.

var js = "alert('test');";
webView.LoadUrl ("javascript:" + js);

iOS

다음과 같이 Javascript를 호출하시면 됩니다.

var js = "alert('test');";
webView.EvaluateJavascript (js);

Razor란?

Razor는 ASP.NET MVC에서 소개된 기능으로써 C#구문을 통해서 간편하게 HTML, CSS, Javascript 구문을 통제하거나 생성할 수 있게 해줍니다. Razor Template는 Model을 지정할 수도 있는데, 이를 통해서 HTML 페이지를 작성하실 때 손쉽게 Model에 접근하고 데이터를 출력하실 수도 있습니다.

Razor Template Basics

Razor는 cshtml확장자를 가집니다. 다음과 같이 Xamarin Project에 cshtml 확장자를 가진 Razor Template파일을 추가하실 수 있습니다.

image

Razor는 다음과 같이 표현될 수 있습니다.

@model string
<html>
    <body>
var template = new RazorView () { Model = "Hello World" };
var page = template.GenerateString ();
<h1>@Model</h1> </body> </html>
  • @는 Razor에서 특별한 의미를 가집니다. @다음의 문자열은 실행될 C#구문이 위치하게 됩니다.
  • 첫줄의 @model은 사용할 Model의 Type을 나타냅니다. 여기서는 전달받을 Model을 string type으로 지정하였습니다. 이 구문은 반드시 첫번째 줄에 위치해야합니다.
  • @Model은 전체 페이지에서 사용하실 수 있습니다. @Model은 Model에 직접접근 하는 코드이며, 이 위치에 전달받은 Model의 정보가 출력되게 됩니다.
  • IDE는 특별한 Partial View를 생성합니다. 이 파일은 수정할 수 없습니다.
    image
  • @using namespace구문을 사용할 수도 있는데, 선언된 namespace에 해당하는 class를 페이지 전체에서 사용하실 수 있습니다.
    @model string
    @using System.IO;
    <html>
        <body>
           <h1>@Path.GetFileName(Model)</h1>
        </body>
    </html>

최종 HTML결과는 다음과 같이 생성될 수 있습니다. Razor 페이지에서 전달받을 Model type을 string으로 지정했기에 아래에서는 Model에 “Hello World”를 넘겨줍니다

var template = new RazorView () { Model = "Hello World" };
var page = template.GenerateString ();

생성된 결과는 다음과 같습니다.

image

 

Razor에 대한 좀더 자세한 사항은 다음 링크를 확인해주세요.