アプリを提供するためのウェブページの準備
アプリサービスのウェブページを設定する¶
アプリユーザーは、アプリをインストールして実行するために以下のステップを踏みます:
- アプリがサービスされているウェブページでアプリ起動ボタンをクリックし、Crossplay Launcherをダウンロードしてインストールします。
- Crossplay Launcherを実行します。
- Crossplay Launcherが自動的にアプリをダウンロードしてインストールします。
- Crossplay Launcherが自動的にアプリを更新して実行します。
以下は、Crossplay Launcherを使用してウェブページからアプリをサービスする全プロセスです。
サービスアプリのウェブページは、以下の2つの方法で提供できます:
- ゲーム (https://withhive.com/)
- アプリを開発した会社が作成したウェブページ。
このガイドでは、クロスプレイランチャーを使用してアプリをウェブページからサービスする際に、ウェブページで実装する必要があることについての例とガイダンスを提供します。アプリ開発者によって構築されたウェブページです。
アプリサービス条件の確認¶
ユーザーがウェブページにアクセスしたとき、ユーザーのPC環境、例えばOSのバージョンがサポートされているか確認します。
- サポートされているOS: Windows 10以上
条件を確認した後、問題がある場合は、エラーポップアップがユーザーに表示されるべきです。
アプリ起動ボタンとクロスプレイランチャーのダウンロードポップアップを実装する¶
Crossplay Launcherのインストールファイルをダウンロードするためのポップアップウィンドウを実装します。ポップアップウィンドウには、Crossplay Launcherのインストールガイドが含まれている必要があります。
ウェブページ上のアプリ起動ボタンをクリックするとポップアップウィンドウが表示されます。ポップアップウィンドウには、Crossplay Launcherのインストールファイルをダウンロードするためのボタンが必要です。
クロスプレイランチャーのインストールを確認する¶
ユーザーがウェブページのアプリ起動ボタンをクリックすると、ユーザーのPCにクロスプレイランチャーがインストールされているかどうかを確認する必要があります。ウェブページで以下のJavaScriptコードを実行して、ユーザーのPCにクロスプレイランチャーがインストールされているかどうかを確認します。
JavaScript コード
!function (b, a) {
"object" == typeof exports && "object" == typeof module
? module.exports = a()
: "function" == typeof define && define.amd
? define("customProtocolCheck", [], a)
: "object" == typeof exports
? exports.customProtocolCheck = a()
: b.customProtocolCheck = a()
}(window, function () {
return function (b) {
var c = {};
function a(d) {
if (c[d])
return c[d].exports;
var e = c[d] = {
i: d,
l: !1,
exports: {}
};
return b[d].call(e.exports, e, e.exports, a),
e.l = !0,
e.exports
}
return a.m = b,
a.c = c,
a.d = function (b, c, d) {
a.o(b, c) || Object.defineProperty(b, c, {
enumerable: !0,
get: d
})
},
a.r = function (a) {
"undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(
a,
Symbol.toStringTag,
{value: "Module"}
),
Object.defineProperty(a, "__esModule", {
value: !0
})
},
a.t = function (b, c) {
if (
1 & c && (b = a(b)),
8 & c || 4 & c && "object" == typeof b && b && b.__esModule
)
return b;
var d = Object.create(null);
if (a.r(d), Object.defineProperty(d, "default", {
enumerable: !0,
value: b
}), 2 & c && "string" != typeof b)
for (var e in b)
a.d(d, e, (function (a) {
return b[a]
}).bind(null, e));
return d
},
a.n = function (c) {
var b = c && c.__esModule
? function () {
return c.default
}
: function () {
return c
};
return a.d(b, "a", b),
b
},
a.o = function (a, b) {
return Object
.prototype
.hasOwnProperty
.call(a, b)
},
a.p = "",
a(a.s = 0)
}({
"./index.js": function (module, exports) {
eval(
'var browser = {\n getUserAgent: function getUserAgent() {\n return window.' +
'navigator.userAgent;\n },\n userAgentContains: function userAgentContains(br' +
'owserName) {\n browserName = browserName.toLowerCase();\n return this.ge' +
'tUserAgent().toLowerCase().indexOf(browserName) > -1;\n },\n isOSX: function' +
' isOSX() {\n return this.userAgentContains("Macintosh");\n },\n isFirefox' +
': function isFirefox() {\n return this.userAgentContains("firefox");\n },' +
'\n isInternetExplorer: function isInternetExplorer() {\n return this.userA' +
'gentContains("trident");\n },\n\n /**\r\n * Detects IE 11 and older\r\n ' +
'* @return {Boolean} Returns true when IE 11 and older\r\n */\n isIE: functi' +
'on isIE() {\n var ua = this.getUserAgent().toLowerCase(); // Test values.\n' +
' // Uncomment to check result\n // IE 10\n // ua = \'Mozilla/5.0 (com' +
'patible; MSIE 10.0; Windows NT 6.2; Trident/6.0)\';\n // IE 11\n // ua =' +
' \'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko/20100101 Fire' +
'fox/12.0\';\n\n var msie = ua.indexOf("msie");\n\n if (msie > 0) {\n ' +
' // IE 10 or older\n return true;\n }\n\n var trident = ua.indexOf' +
'("trident/");\n\n if (trident > 0) {\n // IE 11\n return true;\n ' +
' } // other browser\n\n\n return false;\n },\n isEdge: function isEdge(' +
') {\n var ua = this.getUserAgent().toLowerCase(); // Test values.\n // U' +
'ncomment to check result\n // Edge\n // ua = \'Mozilla/5.0 (Windows NT 1' +
'0.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 S' +
'afari/537.36 Edge/12.10240\';\n\n var edge = ua.indexOf("edge");\n\n if ' +
'(edge > 0) {\n return true;\n }\n\n return false;\n },\n isChrome' +
': function isChrome() {\n // IE11 returns undefined for window.chrome\n ' +
'// and new Opera 30 outputs true for window.chrome\n // but needs to check ' +
'if window.opr is not undefined\n // and new IE Edge outputs to true for win' +
'dow.chrome\n // and if not iOS Chrome check\n var isChromium = window.ch' +
'rome;\n var winNav = window.navigator;\n var vendorName = winNav.vendor;' +
'\n var isOpera = typeof window.opr !== "undefined";\n var isIEedge = win' +
'Nav.userAgent.indexOf("Edge") > -1;\n var isIOSChrome = winNav.userAgent.ma' +
'tch("CriOS");\n return isChromium !== null && typeof isChromium !== "undefi' +
'ned" && vendorName === "Google Inc." && isOpera === false && isIEedge === fals' +
'e || isIOSChrome;\n },\n isWhale: function isWhale() {\n // IE11 returns ' +
'undefined for window.chrome\n // and new Opera 30 outputs true for window.c' +
'hrome\n // but needs to check if window.opr is not undefined\n // and ne' +
'w IE Edge outputs to true for window.chrome\n // and if not iOS Chrome chec' +
'k\n var isChromium = window.chrome;\n var winNav = window.navigator;\n ' +
' var vendorName = winNav.vendor;\n var isOpera = typeof window.opr !== "un' +
'defined";\n var isIEedge = winNav.userAgent.indexOf("Edge") > -1;\n var ' +
'isIOSChrome = winNav.userAgent.match("CriOS");\n return isChromium !== null' +
' && typeof isChromium !== "undefined" && vendorName === "NAVER Corp." && isOpe' +
'ra === false && isIEedge === false || isIOSChrome;\n },\n isOpera: function ' +
'isOpera() {\n return this.userAgentContains(" OPR/");\n }\n};\nvar DEFAULT' +
'_CUSTOM_PROTOCOL_FAIL_CALLBACK_TIMEOUT;\n\nvar registerEvent = function regist' +
'erEvent(target, eventType, cb) {\n if (target.addEventListener) {\n target' +
'.addEventListener(eventType, cb);\n return {\n remove: function remove' +
'() {\n target.removeEventListener(eventType, cb);\n }\n };\n }' +
' else {\n target.attachEvent(eventType, cb);\n return {\n remove: f' +
'unction remove() {\n target.detachEvent(eventType, cb);\n }\n }' +
';\n }\n};\n\nvar createHiddenIframe = function createHiddenIframe(target, uri' +
') {\n var iframe = document.createElement("iframe");\n iframe.src = uri;\n ' +
'iframe.id = "hiddenIframe";\n iframe.style.display = "none";\n target.append' +
'Child(iframe);\n return iframe;\n};\n\nvar openUriWithHiddenFrame = function ' +
'openUriWithHiddenFrame(uri, failCb, successCb) {\n var timeout = setTimeout(f' +
'unction () {\n failCb();\n handler.remove();\n }, DEFAULT_CUSTOM_PROTOC' +
'OL_FAIL_CALLBACK_TIMEOUT);\n var iframe = document.querySelector("#hiddenIfra' +
'me");\n\n if (!iframe) {\n iframe = createHiddenIframe(document.body, "abo' +
'ut:blank");\n }\n\n onBlur = function onBlur() {\n clearTimeout(timeout);' +
'\n handler.remove();\n successCb();\n };\n\n var handler = registerEve' +
'nt(window, "blur", onBlur);\n iframe.contentWindow.location.href = uri;\n};\n' +
'\nvar openUriWithTimeoutHack = function openUriWithTimeoutHack(uri, failCb, su' +
'ccessCb) {\n var timeout = setTimeout(function () {\n failCb();\n handl' +
'er.remove();\n }, DEFAULT_CUSTOM_PROTOCOL_FAIL_CALLBACK_TIMEOUT); //handle pa' +
'ge running in an iframe (blur must be registered with top level window)\n\n v' +
'ar target = window;\n\n while (target.parent && target != target.parent) {\n ' +
' target = target.parent;\n }\n\n onBlur = function onBlur() {\n clearTi' +
'meout(timeout);\n handler.remove();\n successCb();\n };\n\n var handle' +
'r = registerEvent(target, "blur", onBlur);\n window.location = uri;\n};\n\nva' +
'r openUriUsingFirefox = function openUriUsingFirefox(uri, failCb, successCb) {' +
'\n var iframe = document.querySelector("#hiddenIframe");\n\n if (!iframe) {' +
'\n iframe = createHiddenIframe(document.body, "about:blank");\n }\n\n try' +
' {\n iframe.contentWindow.location.href = uri;\n successCb();\n } catch' +
' (e) {\n if (e.name == "NS_ERROR_UNKNOWN_PROTOCOL") {\n failCb();\n ' +
' }\n }\n};\n\nvar openUriWithMsLaunchUri = function openUriWithMsLaunchUri(ur' +
'i, failCb, successCb) {\n navigator.msLaunchUri(uri, successCb, failCb);\n};' +
'\n\nvar getBrowserVersion = function getBrowserVersion() {\n var ua = window.' +
'navigator.userAgent;\n var tem,\n M = ua.match(/(opera|chrome|safari|fir' +
'efox|msie|trident(?=\\/))\\/?\\s*(\\d+)/i) || [];\n\n if (/trident/i.test(M[1' +
'])) {\n tem = /\\brv[ :]+(\\d+)/g.exec(ua) || [];\n return parseFloat(te' +
'm[1]) || "";\n }\n\n if (M[1] === "Chrome") {\n tem = ua.match(/\\b(OPR|E' +
'dge)\\/(\\d+)/);\n\n if (tem != null) {\n return parseFloat(tem[2]);\n' +
' }\n }\n\n M = M[2] ? [M[1], M[2]] : [window.navigator.appName, window.na' +
'vigator.appVersion, "-?"];\n if ((tem = ua.match(/version\\/(\\d+)/i)) != nul' +
'l) M.splice(1, 1, tem[1]);\n return parseFloat(M[1]);\n};\n\nvar protocolChec' +
'k = function protocolCheck(uri, failCb, successCb) {\n var timeout = argument' +
's.length > 3 && arguments[3] !== undefined ? arguments[3] : 2000;\n var unsup' +
'portedCb = arguments.length > 4 ? arguments[4] : undefined;\n\n var failCallb' +
'ack = function failCallback() {\n failCb && failCb();\n };\n\n var succes' +
'sCallback = function successCallback() {\n successCb && successCb();\n };' +
'\n\n var unsupportedCallback = function unsupportedCallback() {\n unsuppor' +
'tedCb && unsupportedCb();\n };\n\n var openUri = function openUri() {\n i' +
'f (browser.isFirefox()) {\n var browserVersion = getBrowserVersion();\n\n' +
' if (browserVersion >= 64) {\n openUriWithHiddenFrame(uri, failCal' +
'lback, successCallback);\n } else {\n openUriUsingFirefox(uri, fai' +
'lCallback, successCallback);\n }\n } else if (browser.isWhale()) {\n ' +
' openUriWithTimeoutHack(uri, failCallback, successCallback);\n } else if' +
' (browser.isChrome()) {\n openUriWithTimeoutHack(uri, failCallback, succe' +
'ssCallback);\n } else if (browser.isOSX()) {\n openUriWithHiddenFrame(' +
'uri, failCallback, successCallback);\n } else {\n //not supported, imp' +
'lement please\n unsupportedCallback();\n }\n };\n\n if (timeout) {\n' +
' DEFAULT_CUSTOM_PROTOCOL_FAIL_CALLBACK_TIMEOUT = timeout;\n }\n\n if (bro' +
'wser.isEdge() || browser.isIE()) {\n //for IE and Edge in Win 8 and Win 10' +
'\n openUriWithMsLaunchUri(uri, failCb, successCb);\n } else {\n if (doc' +
'ument.hasFocus()) {\n openUri();\n } else {\n var focusHandler = ' +
'registerEvent(window, "focus", function () {\n focusHandler.remove();\n' +
' openUri();\n });\n }\n }\n};\n\nmodule.exports = protocolChec' +
'k;\n\n//# sourceURL=webpack://customProtocolCheck/./index.js?'
)
},
0: function (module, exports, __webpack_require__) {
eval(
'module.exports = __webpack_require__(/*! /Users/shahv/Viresh/work/rnd/custom-p' +
'rotocol-check/index.js */"./index.js");\n\n\n//# sourceURL=webpack://customPro' +
'tocolCheck/multi_./index.js?'
)
}
})
})
ユーザーのPCにCrossplay Launcherがインストールされていない場合は、Crossplay Launcherとアプリを一緒にインストールする機能を実装してください。Crossplay Launcherがすでにインストールされている場合は、Crossplay Launcherを実行する機能を実装してください。
Crossplay Launcherとアプリを一緒にインストールする¶
Crossplay Launcherのインストールプロセス中に、アプリも自動的にインストールされ、実行されることがあります。
クロスプレイランチャーインストールファイルをダウンロードするイベントを実装する: インストールファイルをダウンロードする¶
アプリ起動ボタンとポップアップを作成するための上記のガイドを実装した後、ポップアップのダウンロードボタンをクリックしたときに、ユーザーがクロスプレイランチャーインストールファイルをhivecrossplay-fn.qpyou.cn/hivecrossplay/p/w/Installer.exeダウンロードできる機能を実装します。
クロスプレイランチャーインストールファイルをダウンロードするイベントを実装する: 自動アプリインストール¶
ユーザーがダウンロードボタンをクリックすると、自動インストール URIをユーザーのPCのクリップボードにコピーする機能を実装します。クロスプレイランチャーをインストールした後、クロスプレイランチャーはクリップボード内のゲームインストールURIを自動的に検索します。見つかった場合、対応するアプリをインストールします。ゲームインストールURIがクリップボードに見つからない場合、ユーザーのPCにはクロスプレイランチャーのみがインストールされます。アプリをインストールするには、ユーザーはウェブページに戻り、アプリ起動ボタンを再度クリックする必要があります。詳細については、クロスプレイランチャーを実行するCrossplay Launcherを参照してください。
自動インストールURIの取得¶
自動インストールURIをHive コンソール (サンドボックスまたは商用) > クロスプレイランチャー > アプリ管理 > ダウンロード設定 > ランチャーインストール/起動URIから取得します。
# Example
hivelauncher:?app_id=com.com2us.hivesdk.windows.microsoftstore.global.normal&start_point=9 f387268b8ea6c3e0016c8fd41562ed53d4c38338
URIをクリップボードにコピーする¶
取得した自動インストールURIをユーザーのPCのクリップボードスペースにコピーする。
クロスプレイランチャーを実行する¶
ユーザーのPCにクロスプレイランチャーがインストールされたら、ユーザーがウェブページ上のアプリ起動ボタンをクリックするイベントが発生したときに、次のJavaScriptコードを実行します。このJavaScriptコードは、起動URIを使用してクロスプレイランチャーを起動し、クロスプレイランチャーは自動的にアプリをインストールして実行します。
起動URIを取得する¶
URIをHive コンソール (サンドボックスまたはライブ) > クロスプレイランチャー > アプリ管理 > ダウンロード設定 > ランチャーインストール/起動URIから取得します。
# Example
hivelauncher:?app_id=com.com2us.hivesdk.windows.microsoftstore.global.normal&start_point=9
JavaScriptコードを実装して実行する¶
ユーザーのPCにCrossplay Launcherがインストールされているとき、ユーザーがウェブページのアプリ起動ボタンをクリックしたときにJavaScriptコードの実行を実装します。
event.preventDefault
? event.preventDefault()
: (event.returnValue = false);
window.customProtocolCheck({
# Implement executing the launch URI.
# The launch URI launches the Crossplay Launcher. The Crossplay Launcher automatically installs and runs the app.
}, function (e) {
console.log("FAIL");
{
# Handling Crossplay Launcher Execution Failure
}
}, function (e) {
console.log("SUCCESS");
}, 2500, function (e) {
console.log("Not Supported");
{
# Handling No Response After 2500ms from Crossplay Launcher Execution Request
}
});
以下は、「Play on PC」ボタンが押されたときの結果の例です。これにより、JavaScript コードの実行がトリガーされます。Crossplay Launcher が実行されると、ブラウザ通知が表示され、Crossplay Updater を実行するかどうかを尋ねられます。これにより、Crossplay Launcher 自体が更新されます。
Note
Due to the difference between JAVA's URLEncoder.encode()
and JavaScript's encodeURIComponent()
, when implementing the execution of the app in JAVA, the replaceAll("\+", "%20")
operation is required.