結論先行: 對一般玩家而言,第三方 App 目前無法可靠地一鍵把 mod 裝進官方 FNF 手機版。最穩定的仍是 官方手動流程(OPEN DATA FOLDER)。進階變通方案存在,但不適合大眾。
我是在讀這篇 V-Slice 入門與排錯文章時產生這個想法的:
TL;DR: For typical players, a third-party app cannot reliably one-click install mods into official FNF Mobile today. The official manual workflow (OPEN DATA FOLDER) remains the most stable path. Advanced workarounds exist but are not mass-market friendly.
I was reading this V-Slice setup and troubleshooting guide:
Steps:
npm install marked
import { marked } from 'marked';
| #!/bin/bash | |
| # 获取第一个参数 | |
| ARG1="$1" | |
| ROOT_FOLDER="" | |
| SCRIPT_NAME="$0" | |
| SCRIPT_VERSION="1.2.3" | |
| VERSION="" | |
| WEB_FOLDER="" | |
| ORG_INDEX_FILE="index.original.html" | |
| INDEX_FILE="index.html" |
| // JavaScript 根据需要动态加载脚本并设置参数 | |
| // refer to https://xmanyou.com/javascript-dynamically-load-script-and-set-parameters/ | |
| async function loadJsAsync(src:string, async:boolean=false, options?:any) { | |
| return new Promise<void>((resolve, reject) => { | |
| const script = document.createElement('script'); | |
| script.src = src; | |
| script.async = async; | |
| if(options) { | |
| for(const key in options) { | |
| // script[key] = options[key]; |
| // TypeScript/JavaScript 异步等待方法的实现 | |
| // refer to https://xmanyou.com/javascript-wait-until-condition-meet-or-timeout/ | |
| function waitUntil(condition:()=>boolean, timeout?:number, interval?:number) { | |
| if (timeout === void 0) { timeout = 0; } // if not set, wait forever | |
| if (interval === void 0) { interval = 50; } // default interval = 50ms | |
| let waitHandler; | |
| let timeoutHandler; | |
| return new Promise<void>(function (resolve, reject) { | |
| var waitFn = function () { | |
| if (condition()) { |
| function tryCreateShortcutAsync(){ | |
| if(!FBInstant){ | |
| console.info("FBInstant Not Available"); | |
| return; | |
| } | |
| console.info("Try Create shortcut"); | |
| FBInstant.canCreateShortcutAsync() | |
| .then(function(canCreateShortcut) { |
| defaultConfig { | |
| applicationId "com.xmanyou.my.game" | |
| minSdkVersion 21 | |
| targetSdkVersion 30 | |
| versionCode 28 | |
| versionName "1.2.5" | |
| def gitCommit = "git rev-parse --short HEAD".execute().text.trim() | |
| archivesBaseName = "${defaultConfig.applicationId}-${defaultConfig.versionName}v${defaultConfig.versionCode}-${gitCommit}" | |
| println 'outputFileName: after = ' + archivesBaseName |
| module SdkHelper{ | |
| export class IronSourceHelper{ | |
| public static ironsource:Laya.IPlatformClass; | |
| public static init(){ | |
| if(!this.ironsource){ | |
| this.ironsource = Laya.PlatformClass.createClass("sdkhelper.IronSourceHelper"); | |
| } | |
| let js1 = `window["IronSourceHelper"].onInterstitialReadyChange(%s)`; |