[Universal Apps]_Web App Template (WAT) 使用上的操作筆記

Web App Template是一個Universal App的範本

主要是將現有具備良好的響應設計(responsive design)的網站,可以透過這個WAT Template轉化包裝為App。

並且提供額外的Style/JS Injection、 Device硬體連動, Universal App特色設計的UI(例如動態磚)、離線SuperCache 等等額外附加的功能。

 

另外是有強調支援Android跟iOS啦…但本文比較偏向筆記文,只筆記重要的關鍵設定,範疇內只針對Windows平台為主。

 

若你沒有接觸過WAT,建議可以從這個LAB跟著做起:https://github.com/boyofgreen/web-app-HOL/tree/master/hosted-app

不過還是要會一些JS…不過我才剛學完JS就直接實作這個Template,其實也是蠻容易的。

做過上面的Lab會對WAT的一些設定有些概念,下面會補充一些LAB沒提到卻也很重要的部分。

 

 

可以在 http://wat.codeplex.com/ 抓到所需的vsix檔,安裝起來之後你在Visual Studio裡面創立新專案的時候,

在Java Script範本分類底下就會看到多了一個範本稱作 “Web App Template for Universal Apps”

2015-05-13_15-02-11

 

 

另外雖然是Universal App但WAT專案還是有將WP81跟W81平台的部分做比較清楚的切割

但一些我要筆記的功能只會截圖W81 APP的改變,但專案架構彼此雷同,到WP81只需再做更改對照就可以

 


 

 

要讓範本吃到你要載入變為Web App的網址修改的地方在方案的Share專案/config/config.json裡面,改變start_url的值換成你要App化的網站位置

2015-05-13_15-09-57

 

執行看看,其實就只是先單純的把你的Apps套入WAT框架而已,支援Snapview等等…內容的大小改變是取決於網站的設計而非WAT範本喔!

2015-05-13_15-14-10

 


 

 

其實前述的config.json主要是偏向操作App特有功能的設定,可以參考config.sample.json這個檔案裡面的東西

可以做到例如像畫面下方的appbar, 上方的navbar等效果。

 

但記得複製貼過去的時候要注意物件跟物件之間適用逗點隔開,如果執行時有錯誤,先檢查一下格式是否有對,有沒有漏掉分隔符號

以及如果config.json有包含中文,在運行時會卡在loading畫面許久,請檢察config.json是否為UTF-8格式,範本的預設應該是ANSI

 

 

2015-05-13_15-34-33

 

config.sample.json提供的東西包羅萬象,例如“wat_cortana”最潮的Cortana搜尋整合、“wat_secondaryPin”第二個可釘選的動態磚、

“wat_styles” “wat_customScript” WAT WebView內的style/js injection、“wat_settings” “wat_search” “wat_share” CharmBar的相關設定(哭哭..在W10好像要被幹掉了)、

“wat_redirects” 網址跳轉判斷避免轉址的功能(防止USER經由內容跑到其他網頁上)、“wat_offline” 當離線後仍然可以透過Cache機制檢視有限頁面的功能等

 

另外還有“wat_livetile”以及“wat_notifications”分別是處理動態磚還有推撥訊息的功能,但這兩個部分會另外接下來特別說明。

 


 

 

如果你想要在WP81 & W81兩個平台上都隱藏特定的標籤,例如網站上的Copyright聲明等您覺得不適合出現在WebApp的內容

可以在config.json內加入像是以下的內容:

    "wat_styles": {
        "hiddenElements": [
            ".row.footer-copyright.clearfix"
        ],
        "customCssFile._comment": "This enables you to embed CSS styles which get inserted over the existing styles on your website. This is great for adjusting the style of the site when it is presented as an application. This can be used as an alterntive to the injected-styles.css.",
        "customCssFile": "/css/injected-styles.css"
    }

 

在hiddenElements屬性底下可以給予一個陣列,上頭的意思是隱藏class名稱為”row footer-copyright clearfix”的標籤內容,也可以使用id來做篩選,名稱需要依照您要隱藏的內容有所不一樣。


 

 

另外你也可以替使用者加入離線偵測機制,當裝置離線時會跳轉到離線頁面

自訂的離線頁面位於Share/template/offline.html,可以自訂你離線跳轉的離線顯示頁面要長什麼樣子

 

  "wat_offline": {
        "enabled": true,
        "message": "It looks like you are offline. Once network connection is restablished, you will be able to use the To Do application again.",
        "superCache": {
            "enabled": true
        }
    }

 

superCache功能則是會幫UserCache住瀏覽的頁面,以便在離線的情況下仍然可以有限度的瀏覽內容


 

 

另外建議調整一下WAT的Backbutton,官方給那個Button的Div區域實在太大了…如果阻擋到內容,觸控會被吃掉

有多大呢?…看一下下面這張圖,我把backgroud上了色,就知道有多大了:

div1

完全擋住上邊漢堡選單的位置…

 

因此做個CSS的調整

div2

 

調整Share專案底下/css/wrapper-styles.css裡面的內容

.win-backbutton {
    background-color: transparent;
    border-color: rgba(0,0,0,0.7);
    color: rgb(0, 0, 0);
    opacity: 0.6;

    /* 多加下面兩行 */
    margin-left: auto; 
    margin-right: auto;
}

 

        .content .header #backbutton-wrapper {
            -ms-grid-column: 2;
            position: relative;
            z-index: 1;
            background-color: blue;
            opacity: 0.5;
            width: 10px;
            height: 10px;
            margin-top: 60px;
            margin-left: -30px;
            padding-top: 0px;
            padding-bottom: 30px;
            padding-left:0px;
            padding-right:30px;
        }

 

就可以修正了~


 

 

另外關於頁面JS Injection的部分,可以在Share/injection-script-example.js做修改,預設裡面沒東西

我提供一個簡單的範例,是要把頁面所有a連結的href只要有target屬性都給砍掉,因為如果在WAT裡面按下具備target=”_blank”的超連結

就會跳出app重新開一個browser起來瀏覽…這會導致瀏覽體驗低落。

 

所以我就在這裡簡單的寫了一個script去砍掉target屬性以及他的value。

 

// This script will be executed in the context of the webview
var killChildLink = function () {
    console.log("Injection successful la~~~");

    if (document) { 
        var targetItem = document.querySelectorAll("a");
        for (var i = 0; i < targetItem.length; i++) {

            console.log("Remove <a> attribute \"target\": " + targetItem[i].getAttribute("href"));
            
            var textElement = targetItem[i].removeAttribute("target");
             
        };
    }
};

killChildLink();

 


 

 

還有WAT專案的”main()”其實是有的,畢竟他只是一個WinJS骨的App披著WebView顯示網頁內容的template

位於兩個平台個別專案底下的js/default.js

 

預設裡面沒有寫什麼東西,我在這裡做了每次開啟App就去更新tile的功能。

比較tricky的地方在於js/default.js所對應的頁面照理來說應該是在default.html,但在裏頭include其他JS像是JQuery,都沒辦法在js/default.js裡面呼叫…這是蠻奇怪的一件事。

 

後來Trace之後才發現原來要讓js/default.js include其他js需要在template/wat-wrapper.html 裏頭include..

這也是蠻奇怪的邏輯,如果有打include卻在執行時找不到檔案…可能就是你放錯位置

2015-05-13_16-43-15

 

可以參考我自問自答的問題…:http://wat.codeplex.com/discussions/637610

 

下面是我js/default.js的內容,做了更新tile以及測試抓取json的功能,請自行引用JQuery

(function () {
    "use strict";

    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;

     
    

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                // TODO: This application has been newly launched. Initialize
                // your application here.
            } else {
                // TODO: This application has been reactivated from suspension.
                // Restore application state here.
            }
            //args.setPromise(WinJS.UI.processAll());

            args.setPromise(WinJS.UI.processAll().then(function () {
               
                getJson();
                tile.sendTileUpdate("test01", "https://www.ntex.tw/wordpress/wp-content/uploads/2015/04/MVP_Logo_Horizontal_Preferred_Cyan300_RGB_300ppi.png");
               // var test = CommonObject.auth;
                //var fucktile = tile.sendTileUpdate("ntex", "https://www.ntex.tw/wordpress/wp-content/uploads/2015/04/MVP_Logo_Horizontal_Preferred_Cyan300_RGB_300ppi.png");
            }));
        }
    };
   
    app.start();


    ///////////////get json////////////////
    function getJson()
    {
       // var JsonUrl = "http://api.womany.net/api/digest"
        var JsonUrl = "https://www.googleapis.com/freebase/v1/text/en/bob_dylan" 
        
        $.getJSON(JsonUrl, function (data) {
            alert("Data Loaded: " + data);
        });
    }


})();

 

 


 

 

最後Tile的部分,我是參考http://volaresystems.com/blog/post/2012/10/15/Building-a-Windows-8-Live-Tile-with-JavaScript

進行改寫動作,並加上超大型磚的支援

 

code直接給出來了,可以自行trace對照修改效果~

(function () {
    "use strict";
     
    ///////////////tile///////////////////

    // tile格式參照: https://msdn.microsoft.com/en-us/library/windows/apps/hh761491.aspx
    // 相關文件參照: https://msdn.microsoft.com/en-us/library/windows/apps/hh465439.aspx,
    // http://volaresystems.com/blog/post/2012/10/15/Building-a-Windows-8-Live-Tile-with-JavaScript

    function sendTileUpdate(Ttile, ImageUrl) {
        var wideTileXml,
            squareTileXml,
            bigTileXml,
            combinedTileXml,
            tileNotification;

        if (Ttile && ImageUrl) {
            wideTileXml = buildWideTileXml(Ttile, ImageUrl);
            squareTileXml = buildSquareTileXml(Ttile, ImageUrl);
            bigTileXml = buildBigTileXml(Ttile, ImageUrl);
            combinedTileXml = combineTileXml(wideTileXml, squareTileXml, bigTileXml);
            // tileNotification = new Windows.UI.Notifications.TileNotification(wideTileXml);

            tileNotification = new Windows.UI.Notifications.TileNotification(combinedTileXml);
            Windows.UI.Notifications.TileUpdateManager.createTileUpdaterForApplication().update(tileNotification);
        }
    }

    function buildSquareTileXml(Title, ImageUrl) {
        var squareTemplate = Windows.UI.Notifications.TileTemplateType.tileSquare150x150PeekImageAndText02,
                squareTileLines = [
                    Title,
                    ImageUrl
                ],
                squareTileXml = Windows.UI.Notifications.TileUpdateManager.getTemplateContent(squareTemplate),
                squareTileTextAttributes = squareTileXml.getElementsByTagName("text"), squareTileImageAttributes = squareTileXml.getElementsByTagName("image");;

        squareTileTextAttributes[0].innerText = ("文章標題1");
        squareTileTextAttributes[1].innerText = ("文章內容文章內容文章內容1");
        squareTileImageAttributes[0].setAttribute("src", ImageUrl);


        var squareTileBinding = squareTileXml.getElementsByTagName("binding");
        if (squareTileBinding[0]) {
            squareTileBinding[0].setAttribute("branding", "name");
        }

        return squareTileXml;
    }

    function buildWideTileXml(Title, ImageUrl) {
        var wideTemplate = Windows.UI.Notifications.TileTemplateType.tileWide310x150PeekImage01,
                wideTileLines = [
                    Title,
                    ImageUrl
                ],
                wideTileXml = Windows.UI.Notifications.TileUpdateManager.getTemplateContent(wideTemplate),
                wideTileTextAttributes = wideTileXml.getElementsByTagName("text"), wideTileImageAttributes = wideTileXml.getElementsByTagName("image");


        wideTileTextAttributes[0].innerText = ("文章標題2 test");
        wideTileTextAttributes[1].innerText = ("文章內容文章內容文章內容2");
        wideTileImageAttributes[0].setAttribute("src", ImageUrl);



        var binding = wideTileXml.getElementsByTagName("binding");
        if (binding[0]) {
            binding[0].setAttribute("branding", "name");
        }

        return wideTileXml;
    }

    function buildBigTileXml(Title, ImageUrl) {
        var BigTemplate = Windows.UI.Notifications.TileTemplateType.tileSquare310x310ImageAndTextOverlay02,
                BigTileLines = [
                    Title,
                    ImageUrl
                ],
                BigTileXml = Windows.UI.Notifications.TileUpdateManager.getTemplateContent(BigTemplate),
                BigTileTextAttributes = BigTileXml.getElementsByTagName("text"), BigTileImageAttributes = BigTileXml.getElementsByTagName("image");


        // 等價 BigTileTextAttributes[0].innerText = ("文章標題3");
        BigTileTextAttributes[0].appendChild(BigTileXml.createTextNode("文章標題3"));

        // 等價 BigTileTextAttributes[1].innerText = ("文章內容文章內容文章內容3");
        BigTileTextAttributes[1].appendChild(BigTileXml.createTextNode("文章內容文章內容文章內容3"));

        // 等價 BigTileImageAttributes[0].attributes[1].nodeValue = ImageUrl;
        BigTileImageAttributes[0].setAttribute("src", ImageUrl);


        var binding = BigTileXml.getElementsByTagName("binding");
        if (binding[0]) {
            binding[0].setAttribute("branding", "name");
        }

        return BigTileXml;
    }

    function combineTileXml(wideTileXml, squareTileXml, bigTileXml) {

        //var node1 = squareTileXml.importNode(bigTileXml.getElementsByTagName("binding").item(0), true);
        //squareTileXml.getElementsByTagName("visual").item(0).appendChild(node1);

        var node1 = wideTileXml.importNode(bigTileXml.getElementsByTagName("binding").item(0), true);

        var node2 = wideTileXml.importNode(squareTileXml.getElementsByTagName("binding").item(0), true);

        wideTileXml.getElementsByTagName("visual").item(0).appendChild(node1);

        wideTileXml.getElementsByTagName("visual").item(0).appendChild(node2);

        return wideTileXml;
    }

    WinJS.Namespace.define("tile", {
        sendTileUpdate: sendTileUpdate,
        buildWideTileXml: buildWideTileXml,
        buildSquareTileXml: buildSquareTileXml
    });
     

})();

 


 

 

另外PUSH NOTIFICATION步驟比較多我的作法是結合mobile server+notification hubs,但也不會太難,主要要跟AZURE連動

這一部分的說明文件我有找齊放在這了,照著做是OK會成功的~:

 

先做這篇,透過Visual Studio內的AzureSDK完成app端跟azure上面的設定比較方便:

http://azure.microsoft.com/zh-tw/documentation/articles/mobile-services-javascript-backend-windows-universal-dotnet-get-started-push/

 

接著此篇下半部有提供Notification test backend的簡單C#範例程式,可以進行改寫測試推撥訊息是否有WORK:

http://azure.microsoft.com/en-us/documentation/articles/notification-hubs-windows-store-dotnet-get-started/

 


 

 

目前以上是WAT玩到目前的總結筆記,感覺WAT還很多奇形怪狀的功能還沒發揮出來,

 

有需求遇到再提了。

 

以上~

 

 

最後新增幾個在撰文才去找的一些文章,避免發的文章有理解錯誤,產生誤人子弟之嫌

http://www.dotblogs.com.tw/chou/archive/2014/12/09/147583.aspx

http://blogs.msdn.com/b/msdntaiwan/archive/2014/02/10/wat.aspx

http://blogs.msdn.com/b/buildingapps/archive/2014/08/08/web-app-wat-web-app-template.aspx

 

Leave a comment

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料