微信小遊戲分包教程

微信分包教程

 

工具:

修改文件目錄:

起始:

需要修改的地方有 game.json, game.js, main.js

將 raw-assets 分包爲 assets1, assets2,並且壓縮配置上標記文件 game.js 

修改後: 

 

 

 

 

 

修改三個文件 game.json,  game.js, main.js

 game.json  (修改 subpackages對象的屬性)

{
  "deviceOrientation": "portrait",
  "networkTimeout": {
    "request": 5000,
    "connectSocket": 5000,
    "uploadFile": 5000,
    "downloadFile": 5000
  },
  "subpackages": [
    {
      "name": "assets1",
      "root": "res/assets1"
    },
    {
      "name": "assets2",
      "root": "res/assets2"
    }
  ]
}

 

game.js  (保證在引擎渲染前調用nodejs模塊解壓文件到微信的文件系統)



var fs = wx.getFileSystemManager();

let packageNum = 2;
let unzip = (path) => {
    fs.unzip({
        zipFilePath: path,
        targetPath: `${wx.env.USER_DATA_PATH}/raw-assets`,
        success: (res) => {
            console.log('success', res);
            packageNum--;
            if (packageNum == 0) {
                console.log('packageNum', packageNum);
                gameBoot();
            }
        },
        fail: (res) => {
            console.log(res);
        }
    });
};

fs.mkdir({
    dirPath: `${wx.env.USER_DATA_PATH}/raw-assets`,
    success: () => {
        wx.loadSubpackage({
            name: 'assets1',
            success: () => {
                unzip("res/assets1/assets1.zip");
            }
        })

        wx.loadSubpackage({
            name: 'assets2',
            success: () => {
                unzip("res/assets2/assets2.zip");
            }
        })
    },
    fail: () => {
        console.log('fail');
        gameBoot();
    }
})

function gameBoot() {

    require('libs/weapp-adapter/index');
    var Parser = require('libs/xmldom/dom-parser');
    window.DOMParser = Parser.DOMParser;
    require('libs/wx-downloader.js');
    require('src/settings');
    var settings = window._CCSettings;
    require('main');

    // Will be replaced with cocos2d-js path in editor
    require('cocos/cocos2d-js-min.js');

    require('./libs/engine/index.js');

    // Adjust devicePixelRatio
    cc.view._maxPixelRatio = 3;

    wxDownloader.REMOTE_SERVER_ROOT = "";
    wxDownloader.SUBCONTEXT_ROOT = "";
    var pipeBeforeDownloader = cc.loader.subPackPipe || cc.loader.md5Pipe || cc.loader.assetLoader;
    cc.loader.insertPipeAfter(pipeBeforeDownloader, wxDownloader);

    if (cc.sys.browserType === cc.sys.BROWSER_TYPE_WECHAT_GAME_SUB) {
        var _WECHAT_SUBDOMAIN_DATA = require('src/subdomain.json.js');
        cc.game.once(cc.game.EVENT_ENGINE_INITED, function () {
            cc.Pipeline.Downloader.PackDownloader._doPreload("WECHAT_SUBDOMAIN", _WECHAT_SUBDOMAIN_DATA);
        });

        require('./libs/sub-context-adapter');
    }
    else {
        // Release Image objects after uploaded gl texture
        cc.macro.CLEANUP_IMAGE_CACHE = true;
    }
    wxDownloader.init();
    window.boot();
}

main.js (只修改165行下的 rawAssetsBase 屬性 wx.env.USER_DATA_PATH 代表文件系統的路徑, 尾部會默認增加 assets字符變爲 '/raw-assets'

// QQPlay window need to be inited first
if (false) {
    BK.Script.loadlib('GameRes://libs/qqplay-adapter.js');
}

window.boot = function () {
    var settings = window._CCSettings;
    window._CCSettings = undefined;

    if (!settings.debug) {
        var uuids = settings.uuids;

        var rawAssets = settings.rawAssets;
        var assetTypes = settings.assetTypes;
        var realRawAssets = settings.rawAssets = {};
        for (var mount in rawAssets) {
            var entries = rawAssets[mount];
            var realEntries = realRawAssets[mount] = {};
            for (var id in entries) {
                var entry = entries[id];
                var type = entry[1];
                // retrieve minified raw asset
                if (typeof type === 'number') {
                    entry[1] = assetTypes[type];
                }
                // retrieve uuid
                realEntries[uuids[id] || id] = entry;
            }
        }

        var scenes = settings.scenes;
        for (var i = 0; i < scenes.length; ++i) {
            var scene = scenes[i];
            if (typeof scene.uuid === 'number') {
                scene.uuid = uuids[scene.uuid];
            }
        }

        var packedAssets = settings.packedAssets;
        for (var packId in packedAssets) {
            var packedIds = packedAssets[packId];
            for (var j = 0; j < packedIds.length; ++j) {
                if (typeof packedIds[j] === 'number') {
                    packedIds[j] = uuids[packedIds[j]];
                }
            }
        }

        var subpackages = settings.subpackages;
        for (var subId in subpackages) {
            var uuidArray = subpackages[subId].uuids;
            if (uuidArray) {
                for (var k = 0, l = uuidArray.length; k < l; k++) {
                    if (typeof uuidArray[k] === 'number') {
                        uuidArray[k] = uuids[uuidArray[k]];
                    }
                }
            }
        }
    }

    function setLoadingDisplay() {
        // Loading splash scene
        var splash = document.getElementById('splash');
        var progressBar = splash.querySelector('.progress-bar span');
        cc.loader.onProgress = function (completedCount, totalCount, item) {
            var percent = 100 * completedCount / totalCount;
            if (progressBar) {
                progressBar.style.width = percent.toFixed(2) + '%';
            }
        };
        splash.style.display = 'block';
        progressBar.style.width = '0%';

        cc.director.once(cc.Director.EVENT_AFTER_SCENE_LAUNCH, function () {
            splash.style.display = 'none';
        });
    }

    var onStart = function () {
        cc.loader.downloader._subpackages = settings.subpackages;

        cc.view.enableRetina(true);
        cc.view.resizeWithBrowserSize(true);

        if (!true && !false) {
            if (cc.sys.isBrowser) {
                setLoadingDisplay();
            }

            if (cc.sys.isMobile) {
                if (settings.orientation === 'landscape') {
                    cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
                }
                else if (settings.orientation === 'portrait') {
                    cc.view.setOrientation(cc.macro.ORIENTATION_PORTRAIT);
                }
                cc.view.enableAutoFullScreen([
                    cc.sys.BROWSER_TYPE_BAIDU,
                    cc.sys.BROWSER_TYPE_WECHAT,
                    cc.sys.BROWSER_TYPE_MOBILE_QQ,
                    cc.sys.BROWSER_TYPE_MIUI,
                ].indexOf(cc.sys.browserType) < 0);
            }

            // Limit downloading max concurrent task to 2,
            // more tasks simultaneously may cause performance draw back on some android system / browsers.
            // You can adjust the number based on your own test result, you have to set it before any loading process to take effect.
            if (cc.sys.isBrowser && cc.sys.os === cc.sys.OS_ANDROID) {
                cc.macro.DOWNLOAD_MAX_CONCURRENT = 2;
            }
        }

        var launchScene = settings.launchScene;

        // load scene
        cc.director.loadScene(launchScene, null,
            function () {
                if (cc.sys.isBrowser) {
                    // show canvas
                    var canvas = document.getElementById('GameCanvas');
                    canvas.style.visibility = '';
                    var div = document.getElementById('GameDiv');
                    if (div) {
                        div.style.backgroundImage = '';
                    }
                }
                cc.loader.onProgress = null;
                console.log('Success to load scene: ' + launchScene);
            }
        );
    };

    // jsList
    var jsList = settings.jsList;

    if (false) {
        BK.Script.loadlib();
    }
    else {
        var bundledScript = settings.debug ? 'src/project.dev.js' : 'src/project.js';
        if (jsList) {
            jsList = jsList.map(function (x) {
                return 'src/' + x;
            });
            jsList.push(bundledScript);
        }
        else {
            jsList = [bundledScript];
        }
    }

    var option = {
        id: 'GameCanvas',
        scenes: settings.scenes,
        debugMode: settings.debug ? cc.debug.DebugMode.INFO : cc.debug.DebugMode.ERROR,
        showFPS: !false && settings.debug,
        frameRate: 60,
        jsList: jsList,
        groupList: settings.groupList,
        collisionMatrix: settings.collisionMatrix,
    }

    // init assets
    cc.AssetLibrary.init({
        libraryPath: 'res/import',
        rawAssetsBase: wx.env.USER_DATA_PATH + '/raw-',  // 只修改這裏,wx.env.USER_DATA_PATH代表文件系統的路徑, 尾部會默認增加assets字符變爲'/raw-assets'
        rawAssets: settings.rawAssets,
        packedAssets: settings.packedAssets,
        md5AssetsMap: settings.md5AssetsMap,
        subpackages: settings.subpackages
    });

    cc.game.run(option, onStart);
};

// main.js is qqplay and jsb platform entry file, so we must leave platform init code here
if (false) {
    BK.Script.loadlib('GameRes://src/settings.js');
    BK.Script.loadlib();
    BK.Script.loadlib('GameRes://libs/qqplay-downloader.js');

    var ORIENTATIONS = {
        'portrait': 1,
        'landscape left': 2,
        'landscape right': 3
    };
    BK.Director.screenMode = ORIENTATIONS[window._CCSettings.orientation];
    initAdapter();
    cc.game.once(cc.game.EVENT_ENGINE_INITED, function () {
        initRendererAdapter();
    });

    qqPlayDownloader.REMOTE_SERVER_ROOT = "";
    var prevPipe = cc.loader.md5Pipe || cc.loader.assetLoader;
    cc.loader.insertPipeAfter(prevPipe, qqPlayDownloader);

    window.boot();
}
else if (window.jsb) {

    var isRuntime = (typeof loadRuntime === 'function');
    if (isRuntime) {
        require('src/settings.js');
        require('src/cocos2d-runtime.js');
        require('jsb-adapter/engine/index.js');
    }
    else {
        require('src/settings.js');
        require('src/cocos2d-jsb.js');
        require('jsb-adapter/jsb-engine.js');
    }

    cc.macro.CLEANUP_IMAGE_CACHE = true;
    window.boot();
}

PS:

wx.env.USER_DATA_PATH 的路徑:

 

 

2020/6/3更新 一鍵分包 (分成兩個小於4M的包 ,適用於8M資源):

 

SP.js:

var fs = require('fs');
var path = require('path');

var filePath = path.resolve('./res/raw-assets');

//調用文件遍歷方法  
fileDisplay(filePath);

/** 
 * 文件遍歷方法 
 * @param filePath 需要遍歷的文件路徑 
 */

fs.mkdir('./res/assets1', () => {
    fs.writeFile('./res/assets1/game.js', "", () => {
        console.log('sucess');
    })
});

fs.mkdir('./res/assets2', () => {
    fs.writeFile('./res/assets2/game.js', "", () => {
        console.log('sucess');
    })
});

let fileSize = 0;
let maxSize = 4000000;

function fileDisplay(filePath) {
    //根據文件路徑讀取文件,返回文件列表  
    fs.readdir(filePath, function (err, files) {
        if (err) {
            console.warn(err)
        } else {
            //遍歷讀取到的文件列表  
            files.forEach(function (filename) {
                //獲取當前文件的絕對路徑  
                var filedir = path.join(filePath, filename);
                //根據文件路徑獲取文件信息,返回一個fs.Stats對象  
                fs.stat(filedir, function (eror, stats) {
                    if (eror) {
                        console.warn('獲取文件stats失敗');
                    } else {
                        var isFile = stats.isFile();           // 是文件  
                        var isDir = stats.isDirectory();       // 是文件夾  
                        if (isFile) {
                            fs.stat(filedir, (error, stats) => {
                                if (fileSize < maxSize) {
                                    fileSize += stats.size;
                                    let fsNames = filedir.split('\\');
                                    let fsName = fsNames[fsNames.length - 1];
                                    let DirName = fsNames[fsNames.length - 2];
                                    let destDir = './res/assets1/' + DirName;
                                    fs.mkdir(destDir, () => {
                                        fs.writeFile(destDir + '/' + fsName, "", () => {
                                            fs.copyFile(filedir, destDir + '/' + fsName, () => {
                                            });
                                        })
                                    });
                                }
                                else {
                                    let fsNames = filedir.split('\\');
                                    let fsName = fsNames[fsNames.length - 1];
                                    let DirName = fsNames[fsNames.length - 2];
                                    let destDir = './res/assets2/' + DirName;
                                    fs.mkdir(destDir, () => {
                                        fs.writeFile(destDir + '/' + fsName, "", () => {
                                            fs.copyFile(filedir, destDir + '/' + fsName, () => {
                                            });
                                        })
                                    });
                                }
                            })
                        }
                        if (isDir) {
                            fileDisplay(filedir);  // 遞歸,如果是文件夾,就繼續遍歷該文件夾下面的文件
                        }
                    }
                })
            });
        }
    });
}

fs.readFile('./main.js', 'utf-8', function (err, data) {
    let data2 = data.replace("rawAssetsBase: 'res/raw-',", "rawAssetsBase: wx.env.USER_DATA_PATH + '/raw-',");
    fs.writeFile('./main.js', data2, () => {
    });
})

fs.readFile('./game.json', 'utf-8', function (err, data) {
    let data2 = data.replace(" \"subpackages\": []", "\"subpackages\": [  {\"name\": \"assets1\",\"root\": \"res/assets1\"}, {\"name\": \"assets2\",\"root\": \"res/assets2\"}]");
    fs.writeFile('./game.json', data2, () => {
    });
})

let data3 = "var fs = wx.getFileSystemManager(); let packageNum = 2; let unzip = (path) => { fs.unzip({ zipFilePath: path, targetPath: `${wx.env.USER_DATA_PATH}/raw-assets`, success: (res) => { console.log('success', res); packageNum--; if (packageNum == 0) { console.log('packageNum', packageNum); gameBoot(); } }, fail: (res) => { console.log(res); } }); }; fs.mkdir({ dirPath: `${wx.env.USER_DATA_PATH}/raw-assets`, success: () => { wx.loadSubpackage({ name: 'assets1', success: () => { unzip('/res/assets1/assets1.zip'); } }); wx.loadSubpackage({ name: 'assets2', success: () => { unzip('/res/assets2/assets2.zip'); } }) }, fail: () => { console.log('fail'); gameBoot(); } }); function gameBoot() { require('libs/weapp-adapter/index'); var Parser = require('libs/xmldom/dom-parser'); window.DOMParser = Parser.DOMParser; require('libs/wx-downloader.js'); require('src/settings'); var settings = window._CCSettings; require('main'); require('cocos/cocos2d-js-min.js'); require('./libs/engine/index.js'); cc.view._maxPixelRatio = 3; wxDownloader.REMOTE_SERVER_ROOT = ''; wxDownloader.SUBCONTEXT_ROOT = ''; var pipeBeforeDownloader = cc.loader.subPackPipe || cc.loader.md5Pipe || cc.loader.assetLoader; cc.loader.insertPipeAfter(pipeBeforeDownloader, wxDownloader); if (cc.sys.browserType === cc.sys.BROWSER_TYPE_WECHAT_GAME_SUB) { var _WECHAT_SUBDOMAIN_DATA = require('src/subdomain.json.js'); cc.game.once(cc.game.EVENT_ENGINE_INITED, function () { cc.Pipeline.Downloader.PackDownloader._doPreload('WECHAT_SUBDOMAIN', _WECHAT_SUBDOMAIN_DATA); }); require('./libs/sub-context-adapter'); } else { cc.macro.CLEANUP_IMAGE_CACHE = true; } wxDownloader.init(); window.boot(); }"

fs.writeFile('./game.js', data3, () => {
});



function deleteall(path) {
    var files = [];
    if (fs.existsSync(path)) {
        files = fs.readdirSync(path);
        files.forEach(function (file, index) {
            var curPath = path + "/" + file;
            if (fs.statSync(curPath).isDirectory()) { // recurse
                deleteall(curPath);
            } else { // delete file
                fs.unlinkSync(curPath);
            }
        });
        fs.rmdirSync(path);
    }
};


setTimeout(() => {
    deleteall("./res/raw-assets")
}, 2000);

使用:

把 SP.js 放在wechatgame文件夾下,執行

node SP.js :

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章