2020年12月30日 星期三

Electron - 新手入門 - 做一個 windows 鬧鐘應用程式吧

 文章來源:https://dotblogs.com.tw/explooosion/2018/03/25/181604

 

這是一篇適合給新手的入門開發

 

 

 

📝 前言

這一篇算已經遲來了,

以前開發桌面應用程式都是用 WinForm

後來 Electron 的熱門,所以將以往自己寫的軟體重構。

只是一直忘記紀錄成文章。

 

這篇會從基本的開始教學,

包含如何編譯成 Windows 可執行檔(.exe),

以及最後如何封裝起來,給別人進行安裝。

 

⏰ 展示

本專案將以 Windows 作為平台,開發一個桌面的通知程式,

透過指定的時間,當時間到了的時候,會在右下角提醒。

完整專案放置於 Github - electron-alarm-clock

DEMO

 

 

 

📚 本文目錄:

  1. Electron 介紹
  2. 專案建立
  3. 鬧鐘提醒程式開發
  4. 程式編譯
  5. 程式封裝
  6. 建立桌面捷徑
  7. 參考資料

 

 

 

一、Electron 介紹

依照慣例先看一下 Logo

「Electron」的圖片搜尋結果

 

Electron 最早名稱為 Atom Shell

是由 Github 所開發的開源框架,

主要是使用 Node.jsChromium 進行 GUI 桌面 APP 開發。

由於開發環境就是基於 Node.js,請務必安裝好。

 

在學習上當然就需要具備一點 Node.js 基礎,包含 npmpackage.json 的認知與操作。

如果對 Node.js 感到陌生,推薦看這篇文章 😮:

 

很多知名的桌面應用程式都是使用 Electron 開發的例如:

 

關於 Electron 的小八卦

只不過原 Electron 的相關開發人員 👨🏻‍💻,

目前已經重構並轉移到新的專案進行開發 - Yue (官網

有空也會來熟悉下玩玩看 Yue 惹!

 

 

 

二、專案建立

以下實務操作將建立一個桌面鬧鐘通知應用程式,

如果對環境初始已經熟悉,可以直接 clone 官方的 electron-quick-start

 

首先我們建立專案資料夾,並初始化:

mkdir electron-alarm-clock && cd electron-alarm-clock
npm init -y
  • 你可以直接手動新增資料夾,然後進入(可以不用這麼工程師的方式)
  • 進入專案後使用終端機輸入 npm init -y 進行初始專案(-y 是將詢問的條件通通默認 yes)

 

安裝 electron:

npm install --save--dev electron
  • --save-dev 會將指定套件存於 package.json 的 devDependencies
  • 因為 electron 只有開發階段才需要用到,因此只需要 --save--dev

 

修改程式進入點位置:

在 main 的部分,將 index.js 改為 main.js

script 的部分,新增 start

[ package.json ]

{
  "name": "electron-alarm-clock",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^1.8.4"
  }
}

 

建立主程式,因此新增檔案 main.js:

程式說明都在註解中,就不再說明了😖~

[ main.js ]

const {
    app,
    BrowserWindow,
} = require('electron')

const path = require('path')
const url = require('url')

app.on('ready', createWindow)

app.on('window-all-closed', () => {
    // darwin = MacOS
    if (process.platform !== 'darwin') {
        app.quit()
    }
})

app.on('activate', () => {
    if (win === null) {
        createWindow()
    }
})

function createWindow() {
    // Create the browser window.
    win = new BrowserWindow({
        width: 400,
        height: 400,
        maximizable: false
    })

    win.loadURL(url.format({
        pathname: path.join(__dirname, 'index.html'),
        protocol: 'file:',
        slashes: true
    }))

    // Open DevTools.
    // win.webContents.openDevTools()

    // When Window Close.
    win.on('closed', () => {
        win = null
    })

}

 

main.js 中我們指定畫面來源為 index.html

[ index.html ]

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Electron</title>
</head>

<body>
    <h1>Hello Electron</h1>
    <p>Node Version:
        <script>document.write(process.versions.node)</script>
    </p>
    <p>Chrome Version:
        <script>document.write(process.versions.chrome)</script>
    </p>
    <p>Electron Version:
        <script>document.write(process.versions.electron)</script>
    </p>
</body>

</html>
  • 在 script 中,我們可以調用 node.js 的物件,在這邊我們範例使用 process

 

運行結果:

npm start

 

以上我們完成了基本的環境與專案建立。

 

 

 

三、鬧鐘提醒程式開發

這邊基本上可以自行開發創作,

以下功能會進行時間的偵測,並透過 Notification 進行提醒。

 

 

元素布置

首先放置「顯示當前時間的元素」、「可輸入時間的輸入方塊」,

以及載入畫面端主程式 app.js

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Electron</title>
</head>

<body>
    <h1>Hello Electron</h1>
    <p>Node Version:
        <script>document.write(process.versions.node)</script>
    </p>
    <p>Chrome Version:
        <script>document.write(process.versions.chrome)</script>
    </p>
    <p>Electron Version:
        <script>document.write(process.versions.electron)</script>
    </p>
    <hr>
    <div class="now-time"></div>
    <input type="text" class="alarm-time">

    <script src="app.js"></script>
</body>

</html>

 

 

顯示時間並不斷地更新

在時間操作上,我們使用套件 moment.js ⏱,比較方便操作。

npm install --save moment

[ app.js ]

const moment = require('moment')

const elNow = document.querySelector('.now-time')
const elAlarm = document.querySelector('.alarm-time')
elAlarm.addEventListener('change', onAlarmTextChange)

let time = moment()

let nowTime
let alarmTime

/** Set Time */
const now = moment(time).format('HH:mm:ss')
nowTime = now
elNow.innerText = now

const alarm = moment(time).add(5, 'seconds').format('HH:mm:ss')
alarmTime = alarm
elAlarm.value = alarm

timer()

/** Now Time */
function timer() {
    time = moment().format('HH:mm:ss')

    /** Set Now */
    nowTime = time
    elNow.innerText = time

    setTimeout(() => {
        timer()
    }, 1000)
}

/**
 * Save To Global Variable,
 * Can't Read Dom In Minimize Status.
 * @param {event} event
 */
function onAlarmTextChange(event) {
    alarmTime = event.target.value
}
  • 提醒時間:預設當前時間過後 5
  • nowTime:把當前時間存成全域變數

  • alarmTime:把提醒時間存成全域變數

 

可以看到不斷地更新當前時間。

npm start

 

 

提醒時間

判斷時間如果符合提醒,就跳出通知。

[ app.js ]

/** Now Time */
function timer() {
    time = moment().format('HH:mm:ss')

    /** Set Now */
    nowTime = time
    elNow.innerText = time

    check()

    setTimeout(() => {
        timer()
    }, 1000)
}

/** Check Time */
function check() {
    const diff = moment(nowTime, 'HH:mm:ss').diff(moment(alarmTime, 'HH:mm:ss'))
    if (diff === 0) {
        alert('wake up!')
    }
}
  • timer 中呼叫 check

 

當時間到的時候,會跳出訊息。

npm start

 

 

通知訊息

通知的部分,因為在 Windows10 好像 Notification 會有點失效問題 😪,

在這邊選用一個套件 node-notifier 來進行通知。

npm install --save node-notifier

[ app.js ]

const notifier = require('node-notifier')
const path = require('path')
/** Check Time */
function check() {
    const diff = moment(nowTime, 'HH:mm:ss').diff(moment(alarmTime, 'HH:mm:ss'))
    if (diff === 0) {
        const msg = "It's" + alarmTime + ". Wake Up!"
        /** const msg = `It's ${alarmTime}. Wake Up!` */
        notice(msg)
    }
}

/**
 * System Notification
 * @param {string} msg
 */
function notice(msg) {
    /** https://github.com/mikaelbr/node-notifier */
    notifier.notify({
        title: 'Alarm Clock',
        message: msg,
        icon: path.join(__dirname, 'clock.ico'),
        sound: true,
    })
}

 

 

系統通知的圖片使用 [ clock.ico ],請搜尋圖片來用吧,

當時間到的時候,右下會發出系統訊息。

 

 

系統顯示在系統匣

如果要讓系統顯示於右下系統匣,需要使用 Menu、Tray。

[ main.js ]

const {
    app,
    BrowserWindow,
    Tray,
    Menu,
} = require('electron')
function createWindow() {

    // ...

    // Create Tray
    createTray()
}

function createTray() {
    let appIcon = null
    const iconPath = path.join(__dirname, 'clock.ico')

    const contextMenu = Menu.buildFromTemplate([{
            label: 'AlarmClock',
            click() {
                win.show()
            }
        },
        {
            label: 'Quit',
            click() {
                win.removeAllListeners('close')
                win.close()
            }
        }
    ]);

    appIcon = new Tray(iconPath)
    appIcon.setToolTip('Alarm Clock')
    appIcon.setContextMenu(contextMenu)

}

 

可以看到出現在系統匣,而且也有選單。

 

 

畫面縮小時隱藏

[ main.js ]

function createWindow() {

    // ...

    // When Window Minimize
    win.on('minimize', () => {
        win.hide()
    })

    // Create Tray
    createTray()
}

 

縮小的時候,再點選系統匣的 AlarmClock,就可以顯示。

 

提醒的時候顯示表單

如果已經隱藏表單,希望於鬧鐘響的時候顯示表單,

就需要用到 remote,才能從渲染層到主程式 main.js 進行通訊。

[ app.js ]

const remote = require('electron').remote
/**
 * System Notification
 * @param {string} msg
 */
function notice(msg) {
    /** Show Form */
    const window = remote.getCurrentWindow()
    window.restore()
    window.show()

    /** https://github.com/mikaelbr/node-notifier */
    notifier.notify({
        title: 'Alarm Clock',
        message: msg,
        icon: path.join(__dirname, 'clock.ico'),
        sound: true,
    })
}
  • 當觸發 notice 的時候,利用 getCurrentWindow 取得當前表單
  • 這裡的 window.show() 等於從 main.js 進行 win.show()

 

鬧鐘響時,表單從隱藏變成顯示。

 

 

 

四、程式編譯

將程式編譯成 exe,我們使用 electron-packager

package.json 中,新增封裝指令 build

npm install electron-packager --save-dev

[ package.json ]

{
  "scripts": {
    "start": "electron .",
    "build": "electron-packager . AlarmClock --out AlarmClock --overwrite --platform=win32 --arch=x64 --icon=clock.ico --prune=true --squirrel-install --ignore=node_modules/electron-* --electron-version=1.7.9 --ignore=AlarmClock-win32-x64 --version-string.CompanyName=Robby --version-string.ProductName=AlarmClock",
  },
}
  • electron-packager . AlarmClock:把當前目錄 . 打包起來,並將應用程式命名 AlarmClock
  • --out AlarmClock:輸出資料夾於 AlarmClock,產出後預設資料夾為 AlarmClock-win32-x64

  • --overwrite:如果已經存在資料夾和檔案,會進行覆寫

  • --platform=win32:平台為 Windows(Mac: darwin, Linux: linux)

  • --arch=x64:應用程式 64位元(ia32, all)

  • --icon=clock.ico:應用程式 ICON

  • --ignore=node_modules/electron-*:忽略的檔案

  • --electron-version=1.7.9:electron 的核心版本

  • --version-string.CompanyName=Robby:軟體公司名稱(顯示於軟體資訊中)

  • --version-string.ProductName=AlarmClock:軟體名稱(顯示於軟體資訊中)

 

試著編譯看看。

npm run build

應用程式就可以直接執行了!

 

 

 

五、程式封裝

如果想將程式封裝起來,變成安裝版,

這裡分享一個套件 grunt-electron-installer

由於該封裝工具是透過 grunt 運行,所以一併安裝。

npm install --save-dev grunt
npm install --save-dev grunt-electron-installer

 

在根目錄中建立檔案。

[ Gruntfile.js ]

var grunt = require('grunt');

grunt.config.init({
    pkg: grunt.file.readJSON('./AlarmClock/package.json'),
    'create-windows-installer': {
        ia32: {
            appDirectory: './AlarmClock/AlarmClock-win32-x64',
            outputDirectory: './AlarmClock/installer64',
            authors: 'Robby',
            title: 'AlarmClock',
            exe: 'AlarmClock.exe',
            description: 'alarm clock',
            noMsi: true,
            loadingGif: 'clock.ico',
            setupIcon: 'clock.ico',
            icon: 'clock.ico',
        }
    }
})

grunt.loadNpmTasks('grunt-electron-installer');
grunt.registerTask('default', ['create-windows-installer']);
  • AlarmClock/package.json:這個檔案等等我們在輸出的資料夾中 AlarmClock 放置
  • create-windows-installer:grunt 的任務名稱
  • appDirectory: 檔案來源(需要先使用 electron-packager
  • outputDirectory: 輸出資料夾
  • authors: 作者
  • title: 應用程式標題
  • exe: 應用程式名稱
  • description: 應用程式描述(可忽略)
  • noMsi: 是否提供MIS檔(可忽略,預設 true)
  • loadingGif: 執行時的圖片(可忽略)
  • setupIcon: 安裝階段時的圖片(可忽略)
  • icon: ICON圖片

 

[ AlarmClock / package.json ]

接著到輸出資料夾的地方建立 package.json 軟體資訊。

{
    "name": "AlarmClock",
    "version": "1.0.0"
}
  • name:軟體名稱
  • version:軟體版本

 

如果怕混淆,在AlarmClock 中的 package.json 是可以改名的,請注意 Gruntfile.js 所指定的檔名

檔案結構上如下:

 

接著在的 package.json 中,新增封裝指令 pack

[ package.json ]

{
  "scripts": {
    "start": "electron .",
    "build": "electron-packager . AlarmClock --out AlarmClock --overwrite --platform=win32 --arch=x64 --icon=clock.ico --prune=true --squirrel-install --ignore=node_modules/electron-* --electron-version=1.7.9 --ignore=AlarmClock-win32-x64 --version-string.CompanyName=Robby --version-string.ProductName=AlarmClock",
    "pack": "grunt"
  },
}

 

試著封裝檔案 📦。

npm run pack

完成後會出現 Done.

可以在輸出的資料夾 AlarmClock / installer64 看到 👀

 

安裝後的路徑會到哪?

C:\Users\ { 用戶名稱 } \AppData\Local\electron-alarm-clock

 

 

 

六、建立桌面捷徑

避免程式有權限的問題,預設都是安裝在 AppData / Local

由於透過封裝的方式安裝,會發現程式的路徑太長了 😱。

 

避免這樣,

可以在程式安裝階段進行捷徑的建立,

並且在移除階段自動地將捷徑刪除。

[ main.js ]

/** Please Set To The Top */
if (handleSquirrelEvent()) {
    return;
}
function handleSquirrelEvent() {
    if (process.argv.length === 1) {
        return false;
    }

    const appFolder = path.resolve(process.execPath, '..');
    const rootAtomFolder = path.resolve(appFolder, '..');
    const updateDotExe = path.resolve(path.join(rootAtomFolder, 'Update.exe'));
    const exeName = path.basename(process.execPath);

    const spawn = function (command, args) {
        let spawnedProcess;

        try {
            spawnedProcess = ChildProcess.spawn(command, args, {
                detached: true
            });
        } catch (error) {}

        return spawnedProcess;
    };

    const spawnUpdate = function (args) {
        return spawn(updateDotExe, args);
    };

    const squirrelEvent = process.argv[1];
    switch (squirrelEvent) {
        case '--squirrel-install':
        case '--squirrel-updated':
            spawnUpdate(['--createShortcut', exeName]);
            setTimeout(app.quit, 1000);
            return true;

        case '--squirrel-uninstall':

            spawnUpdate(['--removeShortcut', exeName]);
            setTimeout(app.quit, 1000);
            return true;

        case '--squirrel-obsolete':
            app.quit();
            return true;
    }
}

 

這個方式是利用 windows-installer

由於它已經被封裝在 electron-packager,因此不需要另外安裝,直接調用即可 😎。

 

完整專案放置於 Github - electron-alarm-clock

 

 

 

七、參考資料

 

 

2017年4月12日 星期三

從瀏覽器或者 Webview 中喚醒 APP

文章來源:http://blog.html5funny.com/2015/06/19/open-app-from-mobile-web-browser-or-webview/


移動互聯時代,很多互聯網服務都會同時具備網站以及移動客戶端,很多人認為APP的能幫助建立更穩固的用戶關係,於是經常會接到各種從瀏覽器、webview中喚醒APP的需求,顯然,這對於前端開發人員來說,是一件很糾結的事。

喚醒APP

目前常見的主動喚醒APP方式有幾種:

Url scheme

Url scheme是iOS,Android平台都支持,只需要原生APP開發時註冊scheme, 那麼用戶點擊到此類鏈接時,會自動跳到APP。比如
1
2
3
4
<!-- 打開考拉APP首頁 -->
<a href="kaola://www.kaola.com">打開APP</a>
<!-- 呼叫號碼 -->
<a href="tel://13788889999">打開撥號</a>
如果配置scheme的路徑,並在app中識別,則可以直接打開APP特定頁面,如下:
1
2
<!-- 打開考拉APP商品詳情 -->
<a href="kaola://www.kaola.com/product/8342.html">打開APP商品詳情</a>
上述的鏈接,需要考慮手機是否支持此Scheme:
支持:彈出相應程序;
不支持:錯誤處理情況因平台而異,部分app會直接跳錯誤頁(比如Android Chrome/41,iOS中老版的Lofter); 也有的停留在原頁面,但彈出提示「無法打開網頁」(比如iOS7);iOS8以及最新的Android Chrome/43 目前都是直接停留在當前頁,不會跳出錯誤提示。
總體來看, iOS的支持程度比Android好,iOS在實際使用中,除非明確禁止的(比如微信),很少碰到不支持的情況;Android平台則各個app廠商差異很大,比如Chrome從25及以後就不再支持通過js觸發(非用戶點擊),設置iframe src地址等來觸發scheme跳轉

Android intent

這是Android平台獨有的,使用方式如下
1
2
3
4
5
6
7
8
9
intent:
   HOST/URI-path // Optional host 
   #Intent; 
      package=[string]; 
      action=[string]; 
      category=[string]; 
      component=[string]; 
      scheme=[string]; 
   end;
這裡的HOST/URI-path, 與普通http URL 的host/path書寫方式相同, package是Android app的包名,其它參數如action、category、component不是很理解, 具體見文檔 , 比如打開考拉 app的商品詳情,代碼如下
1
2
<!-- 打開考拉APP -->
<a href="intent://www.kaola.com/product/8342.html#Intent;scheme=kaola;package=com.kaola;end">打開APP</a>
如果手機能匹配到相應的APP,則會直接打開;如沒有安裝,則會跳到手機默認的應用商店,比如Google原生系統Nexus 5,將會直接跳到Google Play, 對於國內各廠商定製過的系統,則跳轉到各自的默認應用商店,或者彈出商店供選擇。
intent 比scheme相對完善的一點是,提供一個打開失敗去向URL的選項,可以通過指定參數 S.browser_fallback_url 來指定去向URL。
比如如下的打開APP動作,如果打開失敗,則跳轉到app下載頁,這對於國內的特殊網絡環境,還是挺有用的。
1
2
<!-- 打開考拉APP -->
<a href="intent://www.kaola.com/product/8342.html#Intent;scheme=kaola;package=com.kaola;S.browser_fallback_url=http%3A%2F%2Fapp.kaola.com;end">打開APP</a>

HTTP URL訂閱

Android Chrome平台獨有,app中訂閱自有內容相關的URL,在Chrome中瀏覽相關網頁時,會自動彈出提示,讓用戶選擇用瀏覽器還是APP打開,通用性有限。

iOS內置APP廣告條

在頁面Head中增加meta, 添加智能 App 廣告條 (iOS 6+ Safari), 如下
1
<meta"apple-itunes-app"content"app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL"
可以自動判斷是否已安裝應用, 可惜只能用於iOS+Safari, 在第三方應用中就不行了。
效果如下:

Android Chrome內置app安裝提示

這個是Mobile Chrome 43 beta新加入的特性,在用戶瀏覽某一個網站多次後,如果Chrome發現該站點有原生APP,則會提示用戶下載原生APP,此項特性開發者無法干預,完全是Google的推薦行為,在項目中用不上,具體見新聞報導

實際應用中存在的問題

移動平台提供這麼多喚醒APP的方法,但是功能還不夠完善,以下情況JS無法檢測並做處理:
  1. APP如果喚醒失敗,很多時候都會跳到錯誤頁,影響用戶體驗,而我們的需求很可能是需要跳到下載或者其它頁
  2. APP成功喚醒,頁面無法直接得知,系統沒有提供此類回調。

實際需求、解決方案

  1. 要在打開APP失敗時,不能使當前頁面跳到錯誤頁,且打開失敗時,有失敗函數回調。
  2. 如果成功打開APP,有成功函數回調。
    針對第一點,可以將打開動作放到iframe中,就算跳轉失敗仍能停留在當前頁面;那剩下的問題就是如何檢測APP是否成功打開;
    網上常見解決方案如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //創建一個隱藏的iframe
    var ifr = document.createElement('iframe');
    ifr.src = 'com.baidu.tieba://';
    ifr.style.display = 'none';
    document.body.appendChild(ifr);
    //記錄喚醒時間
    var openTime = +new Date();
    window.setTimeout(function(){
        document.body.removeChild(ifr);
        //如果setTimeout 回調超過2500ms,則彈出下載
        if( (+new Date()) - openTime > 2500 ){
            window.location = 'http://exam.com/xxxx.apk';
        }
    },2000)
此腳本利用了程序切換到後台時,計時器回調會被推遲的原理,如果APP被喚醒,那麼此網頁必然進入後台,如果用戶從APP再切換回來,時間一般也會超過2.5s;如果app沒有喚醒,則setTimeout 基本上會準時回調,時間不會超過2s。但是實際上,這個僅僅在iOS平台有效,Android由於是多任務的,應用放到後台,setTimeout 基本上還是會準時觸發,所以這個邏輯還不夠完善。
那Android 瀏覽器有沒有方法檢測應用是否進入了後台呢? 頁面可見性API(Page Visibility API), 可以通過檢測 document.hiddendocument.[webkit|moz|ms]Hidden 來檢查頁面是否可見,或者訂閱頁面的visibilitychange事件; 如果僅僅應用在新版Android及Chrome上,這個是很美好的,對於老版本(<4.4)及Android Webview, 則不可用。
暮然回首,那人卻在燈火闌珊處,setInterval,對,就setInterval, 如果設置比較小的運行間隔(<30ms),在瀏覽器或者webview中,應用切換到後台,setInterval會被很明顯的延遲執行,比如設置一個運行間隔20ms,總計運行100次的定時器,如果頁面一直處於前台,則100次跑完,總耗時與 100x20=2000ms不會有太大差異,但頁面在後台運行時,此時間會明顯超過2000ms。可以利用這一點來實現是否成功打開APP檢測及回調。
代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function openApp(openUrl, appUrl, action, callback) {
    //檢查app是否打開
    function checkOpen(cb){
        var _clickTime = +(new Date());
        function check(elsTime) {
            if ( elsTime > 3000 || document.hidden || document.webkitHidden) {
                cb(1);
            } else {
                cb(0);
            }
        }
        //啟動間隔20ms運行的定時器,並檢測累計消耗時間是否超過3000ms,超過則結束
        var _count = 0, intHandle;
        intHandle = setInterval(function(){
            _count++;        
            var elsTime = +(new Date()) - _clickTime;
            if (_count>=100 || elsTime > 3000 ) {
                clearInterval(intHandle);
                check(elsTime);
            }
        }, 20);
    }
    
    //在iframe 中打開APP
    var ifr = document.createElement('iframe');
    ifr.src = openUrl;
    ifr.style.display = 'none';
    if (callback) {
        checkOpen(function(opened){
            callback && callback(opened);
        });
    }
    
    document.body.appendChild(ifr);      
    setTimeout(function() {
        document.body.removeChild(ifr);
    }, 2000);  
}
iframe方式打開APP的問題:
  • Android Chrome/25+ 無法打開APP,所以最好是APP配合監聽http URL 來實現。
  • iOS、Android平台,近期發現在沒有安裝對應app時嘗試喚醒,有少數APP會連當前頁面(iframe的父頁面)也變成錯誤頁的情況。
其它問題:
微信無法打開或者下載,打開APP這個基本無解,下載則只能讓應用進駐應用寶市場,然後檢測到在微信中運行時,跳轉到應用寶頁面下載。

2015-11-01 補充

隨著iOS9, Android M的推出, 原先的Scheme URL喚醒app的方式成功率以及很低,並且蘋果還加入了確認機制,使得通過javascript來自動喚醒APP的方式基本不可用。
這兩大平台都推出了自己的WEB與APP連接的方式: Universal Links, App Link, 這部分需要App的開發人員來做了。

iOS 9 學習系列:打通 iOS 9 的通用鏈接(Universal Links)

文章來源:http://www.cocoachina.com/ios/20150911/13321.html


在WWDC 2015 上, Apple 為 iOS 9 宣佈了一個所謂 通用鏈接 的深層鏈接特性, 視頻地址為?[無縫鏈接到您的 App]。雖然它不是一個必須實現的功能, 但還是需要引起一些注意。
在網上有太多讓人迷惑和錯誤的信息, 這次 WWDC 本身也沒有去描述細節。幸運的是, 在 HOKO 我們在我們的智能鏈接上添加了這一特性, 所以我們可以無縫的引導用戶到 APP 上。
什麼是通用鏈接?
很顯然 Apple 正在大力推動 APP 開發者在深層鏈接上有更好的體驗。所有的消息都圍繞著深層鏈接技術。與此同時, Apple 推出通用鏈接:一種能夠方便的通過傳統 HTTP 鏈接來啟動 APP, 使用相同的網址打開網站和 APP。
通過唯一的網址, 就可以鏈接一個特定的視圖到你的 APP 裡面, 不需要特別的 schema 。試想一下 Twitter 使用了通用鏈接, 那麼你每在 twitter。com 點擊一個鏈接, 你的 iOS 設備都會在 Twitter 裡面自動打開這個頁面, 而不是當你沒有安裝時轉到普通的網頁。這個用戶體驗是順暢的, 最重要的是用戶不會失去上下文(跳到 APP 後 Safari 上不再留下空標籤)。
準備使用通用鏈接
實現通用鏈接不難, 但首先必須遵守一些先決條件。如下:
  • 有一個註冊的域名
  • 通過 SSL 訪問域名
  • 支持上傳一個 JSON 文件到你的域名
  • 至少 iOS 9 beta 2 版本 [下載],這很重要, 因為如果是之前的測試版本你需要做額外的操作。
  • 至少 Xcode 7 beta 2 [下載]
如果你都有了, 那就來按照下面3個步驟來做吧。
1.添加域名到 Capabilities
首先, 你必須在 Xcode 的 capabilities 裡 添加你的 APP 域名, 必須用 applinks: 前置它:還添加一些你可能擁有的子域和擴展(www.domain.com, news.domain.com 等等)。
apple_capabilities.png
用 applinks: 前綴添加所有域名, 同時不要忘了包含所有可能需要的子域名*
這將使你的 APP 從你的域名請求一個特殊的 JSON 文件 apple-app-site-association。當你第一次啟動 APP,它會從?https://domain.com/apple-app-site-association?下載這個文件。跳到下個步驟來瞭解如何構建這個文件。
2.上傳 apple-app-site-association 文件
該文件必須存在且為了安全原因可使用?SSL?通過?GET?請求訪問到。你可以打開一個文本編輯器然後寫一個這樣的簡單?JSON?格式:
1
2
3
4
5
6
7
8
9
10
{
??"applinks":?{
????"apps":?[],
????"details":?{
??????"TBEJCS6FFP.com.domain.App":?{
????????"paths":[?"*"?]
??????}
????}
??}
}
根據 paths 鍵設定一個允許的路徑列表(你希望APP 作出反應的路徑), 或只是一個星號如果你想打開 APP 而不管路徑是什麼。
你可能想知道?TBEJCS6FFP.com.domain.App?從何而來, 基本上, 它是加入了你的團隊標識的?bundle id。你可以從你的 [蘋果開發賬號頁面]獲取你的團隊標識:
45.png
這個頁面有你的團隊標識, 你可以拷貝粘貼到 apple-app-site-association 文件
Bundle id 可以在項目的 target -- General 中找到:
1.png
檢查 General 標籤並拷貝粘貼 bundle id 到 apple-app-site-association 文件
最後, 上傳這個文件到你的域名根目錄。如果你打開?https://domain.com/apple-app-site-association?可以看到你的文件, 那麼你就可以繼續下一步了。
3.在 APP 裡處理通用鏈接
為了在 APP 裡支持通用鏈接, 你需要在 AppDelegate 裡實現 [application(_:continueUserActivity:restorationHandler:)]。 儘管這種方法可以用於許多不同的目的(比如 [Handoff]和 [搜索 API]), 我們將只關注如何處理接收到的通用鏈接。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import?UIKit
 
extension?AppDelegate?{
????func?application(application:?UIApplication,?continueUserActivity?userActivity:?NSUserActivity,?restorationHandler:?([AnyObject]?)?->?Void)?->?Bool?{
????????if?userActivity.activityType?==?NSUserActivityTypeBrowsingWeb?{
????????????let?webpageURL?=?userActivity.webpageURL!?//?Always?exists
????????????if?!handleUniversalLink(URL:?webpageURL)?{
????????????????UIApplication.sharedApplication().openURL(webpageURL)
????????????}
????????}
????????return?true
????}
????
????private?func?handleUniversalLink(URL?url:?NSURL)?->?Bool?{
????????if?let?components?=?NSURLComponents(URL:?url,?resolvingAgainstBaseURL:?true),?let?host?=?components.host,?let?pathComponents?=?components.path?.pathComponents?{
????????????switch?host?{
????????????case?"domain.com":
????????????????if?pathComponents.count?>=?4?{
????????????????????switch?(pathComponents[0],?pathComponents[1],?pathComponents[2],?pathComponents[3])?{
????????????????????case?("/",?"path",?"to",?let?something):
????????????????????????if?validateSomething(something)?{
????????????????????????????presentSomethingViewController(something)
????????????????????????????return?true
????????????????????????}
????????????????????default:
????????????????????????return?false
????????????????????}
????????????????}
????????????default:
????????????????return?false
????????????}
????????????
????????}
????????return?false
????}
}
如果提供的 userActivity 是 NSUserActivityTypeBrowsingWeb 類型, 那麼意味著它已經由通用鏈接 API 代理。這樣的話, 它保證用戶打開的 URL 將有一個非空的 webpageURL 屬性。依據前面的例子, 這將是?http://domain.com/path/to/thezoo?的體現。
為了確保你的 APP 可以翻譯 URL 成實際的內容, 你需要做下面幾步:
  • 使用 [NSURLComponents]簡單解析 webpageURL 到 host(如domain。com), 路徑組成同理(如 ["/"]、"path"、"to"以及"thezoo")。
  • 確保能識別 host。
  • 嘗試將 pathComponents 匹配到 APP 的已知內容裡。
  • 驗證該內容實際上可以被呈現。
  • 呈現內容給用戶。
如果上述步驟有任何一個失敗, Apple 建議你的 APP 應該在 Safari 上打開 webpageURL 以顯示錯誤。
總結如圖:
15.png
上圖是通用鏈接的工作流程的概要
通用鏈接的缺點
通用鏈接對於開發人員來說是一個好主意, 但也有一些缺點可能會導致不受青睞。
通用鏈接只適用於 iOS 9 +
配置 APP 支持通用鏈接意味著只有運行 iOS 9 的用戶才能享用這一技術優勢。 而之前版本的用戶將不能在點擊網頁鏈接時打開 APP。 相反的, 他們將返回到瀏覽器和網頁, 就像之前正常的網頁鏈接一樣。
然後, HOKO為 iOS 5 及更高版本的用戶提供了移動深層鏈接。 因此, 你的移動深層鏈接將可以運行在幾乎所有的 iOS 設備上, 不管它們是不是 iOS 9。
通用鏈接總是會返回到先前創建的網頁
如果你想退回主頁或與 APP 完全不不相關的網站?實現這一目標需要一些額外的工作, 要配置一個網頁可以指引用戶到你的目標頁面。 此外, 如果你沒有一個網站的話, 這將會是一個不可能的解決方案。
你可以使用 HOKO 智能鏈接和他們自適應的返回來輕鬆的解決這個問題。 對於創建的每個智能鏈接, 你可以在每個平台上選擇如果沒有安裝 APP 會發生什麼。 另外你可以設置返回到你的網站, iTunes 商店頁面或其它外部網站。
使用通用鏈接, 開發者必須部署一個網站來關聯 APP
這對於小型開發者來說可能是個壞消息, 他們可能買不起或維護一個網站, 但是仍然想通過網頁鏈接進入他們的 APP。?
HOKO 可以解決這個問題因為它來充當開發者的網站, 每個 APP 託管在不同的子域。 因此, 開發者只需創建智能鏈接, 並發布其網址, 然後每次都會無縫的打開相應的 APP。
APP 與網站之間的聯繫是由創建和託管在開發者網站上的配置文件搞定的
使用 HOKO, 你可以跳過這些繁的配置, 因為我們使它可以開箱即用。 此外, 我們的服務器運行在有行業頂級標準的安全性和性能上, 為每個設備提供安全和快速的方式。
如果你想瞭解更多關於 HOKO 的信息, 可以給我們發郵件或直接註冊
(或直接檢查我們關於Google's App Links的詳細指南)

關於 AppLinks 兩三事

文章來源:https://blog.patw.me/archives/1080/something-about-app-links/


前言

在行動裝置時代,使用者更常停留在 App 中瀏覽資訊(像是 Facebook),而相對地在 Web 的停留時間就降低了。過去我們在 Web 上透過超連結搭起不同網站之間的橋,而在 App 與 App 之間又如何做到這件事呢?
當然,我們可以透過 URL Scheme 開啟應用程式,但我們並無法得知世上每個 App 的 URL Scheme,甚至是應用程式某個頁面 Deep Link 的 Scheme,而且萬一哪天增修了那又該如何?
我最近一部分的工作就在研究如何加強 App 於 Mobile Web 上的連結體驗,其實各大廠早提出了自己的構想及標準,例如 Google 提出的 App Indexing,以及 Facebook 提出的 App Links。
今天就 App Links 的部份做個簡單筆記與實作參考。App Indexing 等下次有空再寫文介紹囉。

App Links

為了要解決 App 跟 App 之間相互跨越連結的問題,Facebook 在 2014 年 4 月的 f8 開發者大會上提出了 App Links 的標準。
按照這個標準實作的 App,就可以透過 AppLinks 標準設定的參考,達到 App 之間的跳轉應用。

使用情境

上面的介紹看完可能還是霧煞煞,什麼是 App 之間的跳轉呢?
假設我今天在 Facebook 上看到一則分享連結,這是 小P 購物(我亂取的 XD)的網站、A 商品的頁面,而 小P 購物也有自己的 Android/iOS App(剛好我也有裝),要是我點擊那篇分享連結就自動開啟 小P 購物 App,並且是 A 商品的頁面。
這樣就是從 Facebook 的 App 跳轉到 小P 購物的 App,如此的體驗更為無縫且順暢(如果 小P 購物 App 本身設計的很糟那是另一回事了 :P)
過去我們在動態時報上看到分享連結,點擊就僅僅能到網站、或是 Google Play/App Store 的下載頁面,若加上 App Links 的設定,那麼更能將使用者帶入 App 的深層連結中,提昇轉換率(像是促成購物等行為)。

實作

由於我不是 App 工程師,這邊就不介紹 App 端的實作了,詳情請參考 Facebook 官方文件的介紹
而就 Web 端而言,App Links 的設定其實是放在網頁上的(如果本來就沒網站,只有個 App,那也可以透過 Facebook 提供的 Hosting API 達成),開發者只要把相關的設定(例如 Android、iOS 的 url scheme,以及 package name/App Store ID 之類的設定)加到目標網頁的 <head></head> 區塊中就可以了,不過是幾個 <meta /> 標籤即可完成。
直接來看實例跟實測擷圖(有圖有真相!)。
例如 小P 購物的商品頁上加入了下面這段 HTML:
<!-- Android: 商品 123 的 URL Scheme -->
<meta property="al:android:url" content="partnerapp://product/123">
<!-- Android Package Name,這可以讓使用者在未安裝的時候連結至安裝連結 -->
<meta property="al:android:package" content="partner.ecapp">
<!-- Android: App 名稱,這會出現在使用者未安裝 App,叫你去下載某某 App 的那個文案 -->
<meta property="al:android:app_name" content="Partner Studio">

<!-- iOS: 商品 123 的 URL Scheme -->
<meta property="al:ios:url" content="partnerapp://product/123" />
<!-- iOS: App Store ID,這可以讓使用者在未安裝的時候連結至安裝連結 -->
<meta property="al:ios:app_store_id" content="123456789" />
<!-- iOS: App 名稱,這會出現在使用者未安裝 App,叫你去下載某某 App 的那個文案 -->
<meta property="al:ios:app_name" content="Partner Studio" />

<!-- 要在使用者未安裝 App 的時候自動 fallback 帶使用者到網頁版嗎?預設是 true,若設為 false,則 Facebook 會問使用者是否要下載該 App,或是直接去網頁 -->
<meta property="al:web:should_fallback" content="false" />
塞好之後,可以去 Facebook 的 Debugger 送出目標網址測試看看,若沒有設錯的話應該可以正常看到 App Links 的區塊,就像這樣:
Debugger
最後來看一下使用者操作的擷圖:
Android FB 動態時報
Android 點擊 FB 貼文(未安裝的情況)
iOS FB 動態時報
iOS 點擊 FB 貼文(未安裝的情況)
已安裝 App 的就不擷囉,因為直接是跳轉到 App 裡面了。
好!那麼這就大功告成了!

結語 + 牢騷

雖然行動時代 App 很重要,但使用者的體驗還是第一,個人實在受不了那種從 Facebook 動態時報上點連結過去,還沒看到想看的內容,就跳個插頁式廣告(interstitial ads)叫使用者「下載 App 以瀏覽內容」的作法,這樣跟內容農場必須點讚才讓人看內容有什麼差別!!XD 讓人根本不想點那些連結了,連 Google 的研究報告 也這樣說啊。
我有時候只是想在通勤時看一下內容啊… 為何要逼迫我下載 App 呢?而且這樣網站存在的意義是什麼…只是跳板嗎?好吧,也許 App 下載量是該公司的 KPI 吧…(攤手)

2016年10月4日 星期二

APP 開發新選擇 Corona SDK

文章來源:http://www.runpc.com.tw/content/content.aspx?id=109808


隨著App市場爆炸性的發展,如何快速開發出高品質的App也成為一個重要的議題。目前兩主流大行動裝置平台為Android與iOS,為了擴增市場與滿足使用者的需求,同時開發App於這兩大不同平台是勢在必行的。然而Android與iOS所使用的語言與開發工具全然不同,若想要兩者兼備代表著必須維護兩套不同的專案,無論開發、除錯或測試都會需要兩倍以上的心力。慶幸的事,目前市面上提供了許多跨平台的開發工具,讓使用者只需要撰寫一套程式碼就可以將App同時發佈於不同的平台。知名的跨平台開發工具包括Phone Gap、App Accelerator、Unity 3D、Adobe Flash等等。每個同的跨平台開發工具都有其特色,適合不同的開發者與開發不類型的App。而本篇文章將介紹一款跨平台的軟體開發工具-Corona SDK。雖然目前在台灣較鮮為人知,但其國外的社群已經茁壯到一定的程度,而其網路上的各種資源也是相當豐富。這款開發工具最強大之處在於可以快速開發出酷炫的的遊戲以及各種不同類型的App,關鍵在於其使用一套易於學習的語言Lua作為開發基礎,並且提供近千個強大API讓開發者可以輕易撰寫出複雜的特效或功能,我們將在接下來的段落中詳細介紹其優點與特色。

Corona SDK,不是啤酒
  Corona SDK對大部分人來說相當陌生,可能第一時間想到的是便利超商販賣的啤酒,其實Corona SDK在很久以前就已經引起了世界的注意,那是因為一位14歲的小男孩利用其撰寫了一個名為Bubble Ball的免費遊戲,該遊戲打敗Angry Bird並在iTunes Store蟬聯兩週下載量冠軍。這個消息讓眾人相當驚訝,因為開發App並不是一件相當容易的事,而一位14歲的小男孩居然可以透過Corona SDK寫出高品質的遊戲,也因此讓讓人們開始感到好奇Corona SDK究竟是什麼東西。
  Corona SDK是由兩位Adobe公司離職員工所創辦,他們都在曾Adobe公司擔任重要的角色,其中一位更是Flash Lite Team的首席工程師。他們離職後隨即在2007年成立Corona Labs,並在2009年發佈了Corona SDK 1.0,當時尚未有跨平台的功能,只能針對iPhone進行開發。一直到了2010年其發佈了Corona SDK 2.0以及Corona Game Edition Beta,開始可以支援跨平台並且提供各種方便撰寫遊戲的API。

Corona SDK的優點
1.簡單易學
  Corona SDK所使用的語言為Lua,而Lua是一套輕量級的腳本語言,本身語法相當簡易直覺,Corona SDK包裝了各種API讓使用者可以透過Lua語言呼叫直接使用。假設原生語言需要10行程式碼才能完成的事情,Corona SDK可以將這件事簡化到一行程式碼。少量程式碼的好處是讓開發者可以更專注於App內容的設計,而更少的程式碼也代表著更清楚易懂的程式架構與更少的除錯時間。

2.完善的API支援
  Corona SDK提供了各種完善的API讓開發者可以輕易的使用手機硬體的本身功能如:地理位置系統、加速度計、羅盤等等,而針對其他額外的功能如推播訊息、廣告、In App Purchase等等,Corona SDK通通做了完善的支援。甚至針對社群方面,也有Facebook的API可以呼叫。

3.強大的遊戲API
  Corona SDK最大的賣點就是其對遊戲功能的支援。開發者下載安裝完Corona SDK之後不需再做任何額外的環境設定即可開始使用其內建的功能開發遊戲。其支援的遊戲功能包括:物理引擎、Sprite Sheet、動畫、繪圖處理等等,而這些遊戲功能API的語法也相當直覺易用,對於快速開發遊戲而言是一大利器。

4.豐富的線上資源
  雖然Corona SDK的網路社群並沒有辦法和Android與iOS相提並論,但是官方對於社群的維護相當重視,在官網提供了一個討論版」Share Code」,讓資深的開發人員可以把自己撰寫好的Sample Code分享。該討論板大部分的Sample Code保持良好的品質與清楚的說明,讓初學者可以輕鬆的使用這些範例。當使用者碰到任何問題時,官方的也往往會在第一時間回應說明。

實戰Corona SDK
  接下來我們將透過範例程式碼來介紹Corona SDK的內容與特色,讀者可以透過簡單的範例瞭解Corona SDK的運作方式,以及其對遊戲方面的支援。下列範例中我們將先介紹Corona基本的語法與函式呼叫,接著將介紹Corona最強大的功能之一-物理引擎。

(1)基本功能
(1.1) Hello World
  不免俗的第一個範例程式還是Hello World,在Corona SDK精簡的於法之下,只需要一行程式碼即可完成:

local myTextObject = display.newText( "Hello World!", 50, 50, "Arial", 30 )
程式碼解析:
display是Corona SDK所提供的API,可以用來產生文字、圖案、線條、抓取螢幕以及各種針對顯示物件的操作,簡而言之就是負責處理與呈現有關的功能。而display.newText則會產生一個text物件,我們宣告一個區域變數myTextObject來指向這個新產生出來的物件,這樣之後才有辦法刪除或回收這個text物件。而display.newText這個方法當中第一個參數代表顯示的文字訊息,第二與第三個參數代表著X與Y座標的位置,第四個參數代表著字型,最後一個參數則代表著字型大小。下圖是執行測試後的結果,這樣就完成了最基本的Hello World。


(1.2) Text Color Changer
  接下來我們將Hello World範例程式增加一點變化性,只要使用者用手指點擊螢幕就可以隨機變換」Hello World」字體的顏色。

local myTextObject = display.newText( "Hello World!", 50, 50, "Arial", 30 )

function screenTap()
local r = math.random( 0, 255 )
local g = math.random( 0, 255 )
local b = math.random( 0, 255 )
myTextObject:setTextColor( r, g, b )
end

display.currentStage:addEventListener( "tap", screenTap )

程式碼解析:
在第3~8行我們宣告了一個函式screenTap(),用來處理螢幕點擊事件。screenTap()一接收到螢幕點擊事件,會先透過math.random隨機產生紅綠藍三種顏色的數值,並透過這些數值設定myTextObject的字體顏色。接著我們透過display.currentStage可以抓取到目前螢幕畫面,再利用addEventListner可以監聽點擊事件」tap」,當產生點擊事件時會自動呼叫我們所定義的screenTap()函式,這樣就完成了一個可以切換字體顏色的基本範例。參考下圖為輸出結果:


(2)物理引擎 Corona SDK最棒的功能之一大概就是物理引擎了,因為Corona SDK內建Box 2D這套物理引擎,開發者完全不需作額外的環境設定,透過幾行程式碼就可以實作出物理引擎的效果,接下來馬上透過範例來看如何使用物理引擎。

(2.1) Sky Faller
  這個範例中我們將會設定兩個擁有物理屬性的物件,分別是由上往下掉落的箱子以及靜止不動的地板。程式一開始箱子會在螢幕正上方,而物理引擎開始運作之後箱子便會因為重力而掉落,與地板接觸之後產生碰撞並滾落一旁。實作的程式碼如下:

local physics = require( "物理" )
physics.start()

local sky = display.newImage( "bg_sky.png" )

local ground = display.newImage( "bg_ground.png" )
ground.x = 160; ground.y = 445

physics.addBody( ground, "static", { friction=0.5, bounce=0.3 } )

local crate = display.newImage( "crate.png" )
crate.x = 180; crate.y = -50; crate.rotation = 5

physics.addBody( crate, { density=3.0, friction=0.5, bounce=0.3 } )

程式碼解析:
  在程式碼的第1~2行,分別代表產生一個可以控制物理引擎的物件並開始使用物理引擎。關鍵字requir代表產生一個類別物件,而require內的關鍵字」physics」是Corona SDK針對物理引擎所提供的API類別。而透過require(「physics」)產生物理引擎的物件之後,便可以進行各種物理引擎進行操作,如start、stop等等…。
  第4行與第6行則是透過display.newImage這個API來產生圖片物件,分別設定背景圖天空與地板。第7行則是設定地板圖片物件的位置,讓它處於螢幕下方,這樣箱子才可以由上往下墜落在其上方。第9行則是透過我們之前宣告的physics物件讓地板擁有物理的特性,而這邊的關鍵字」static」讓地板可以靜止不動,」friction」與」bounce」則可以設定地板的摩擦例與彈性。最後的在11~14行的部份我們則是產生了箱子的圖片物件,同樣地透過physics這個物件讓它擁有物理引擎特性。當一切設定完畢按下執行便可以看到箱子由上往下墜落並與地板碰撞彈跳的效果。


(3)實作小結
以上範例中,我們實作了Corona SDK的基本的操作以及其重要特色物理引擎,可以發現透過短短幾行程式碼Corona SDK就可以幫我們完成許多事情。若想透過原生的語言如Java、Objective C在15行內寫出一個物理引擎的範例,那幾乎是不可能的。因此Corona SDK在製作遊戲或者App方面,的確提供了一個更快速的管道。

Corona SDK的美中不足
  雖然Corona SDK有許多優點與特色,但仍然有一些待改善的地方。第一點是Corona SDK沒有自己的整合開發環境,通常開發Lua都是透過簡單的文字編輯器,因此沒辦法進行自動編譯除錯,往往只能在執行期才能知道錯誤的地方。第二點依然與開發環境有關,Corona SDK沒有辦法透過傳輸線直接執行於手機裝置,若想要實機測試,只能先將程式碼透過佈署的方式編譯成.apk或.app再安裝於手機裝置。而佈署時必須與期官方網站連線認證使用者身份,這將導致在沒有網路的情況下將無法實機測試App。

結論
  Corona SDK是一套簡單易學的跨平台開發工具,對於想要快速開發遊戲的開發者來說是一個非常棒的選擇。其簡易的語法與強大的API可以幫助開發者在最短時間內開發出酷炫的遊戲或各種類型的App。使用Corona SDK開發App不用擔心其對於裝置操作方面的支援,因為不管是任何裝置的操作如加速度計、地理位置系統、指南針等等其都有良好的支援。Corona SDK另外也支援In App Purchase、廣告、Facebook等等額外的功能,整體來說Corona SDK在功能性支援方面來講有接近滿分的表現。其美中不足之處在於缺乏專屬的整合開發環境,也無法透過傳輸線直接在實機執行測試,這些都是Corona SDK必須加強改善的地方。