Game reloads or crashes on iPhone when loading assets from multiple Remote Bundles (Cocos Creator v3.8.1)

Game reloads or crashes on iPhone when loading assets from multiple Remote Bundles (Cocos Creator v3.8.1)

Hello everyone,

I’m developing a game using Cocos Creator v3.8.1, targeting both native and HTML5 platforms.
The game is split into 29 remote bundles, each representing a mini game. The sizes of the bundles range from 128.6 KB to 20 MB.

During gameplay:

  • I load all assets from a bundle when a mini game is opened, and after that, load assets from the next bundle to switch to a different mini game.
  • This process continues with load – switch – load.

The issue:

  • On mobile browsers (Safari/Chrome) and native app (iPhone 8 Plus), the game either reloads or crashes after loading assets from about 10 bundles. However, the exact number of bundles is uncertain, and the chances of the crash/reload occurring increases with the more assets loaded.
  • Test device used: iPhone 8 Plus (older iOS).
  • Tests on Android (Note 9) have no issues.

The code responsible for loading assets:

loadAny(...args: any[]): Promise<Asset[]> {
    return new Promise(async (resolve, reject) => {
        try {
            let [assets, options, onProgress, onComplete] = args;
            options = options ?? {};  // If options is not provided, initialize as an empty object
            const loadPromises = assets.map((assetsInfo) => {
                return new Promise<AssetManager.Bundle>((res, rej) => {
                    const { bundle } = assetsInfo;
                    ResourceMap.log(`[ResourceMap] loadAny assetsInfo`, assetsInfo);
                    if (bundle && bundle.length > 0 && cc[`settings`].querySettings("assets", "projectBundles").includes(bundle)) {
                        this.loadBundle(bundle).then(() => {
                            res(assetsInfo);
                        }).catch((err) => {
                            ResourceMap.error(`[ResourceMap] loadAny err`, err);
                            res(null);
                        });
                    } else {
                        res(assetsInfo);
                    }
                });
            });
            // Wait for all promises to complete
            let results = await Promise.all(loadPromises);
            // Filter out any null results
            assets = results.filter(result => result !== null) as AssetManager.Bundle[];
            // After preloading completes, move to the loading phase
            await this.loadAssetsInParallel(assets, options, (loaded, total) => {
                if (onProgress) {
                    onProgress(loaded, total); // Forward progress during preload phase
                }
            }, (err, results) => {
                if (err) {
                    if (onComplete) {
                        onComplete(err); // Complete callback after loading
                    }
                    resolve(results); // Resolve with the data after both preloading and loading
                } else {
                    if (onComplete) {
                        onComplete(null, results); // Complete callback after loading
                    }
                    resolve(results); // Resolve with the data after both preloading and loading
                }
            });
        } catch (error) {
            reject(error); // Reject the promise in case of any error
        }
    });
}
loadAssetsInParallel(assets, options, onProgress, onComplete) {
        let total = assets.length;
        let loaded = 0;
        const assetLoadingPromises = assets.map((asset) => {
            return new Promise((resolve, reject) => {
                if (this.uuidMap.has(asset.uuid)) {
                    loaded++;
                    if (onProgress) {
                        onProgress(loaded, total); // Forward progress during preload phase
                    }
                    resolve({ asset: this.uuidMap.get(asset.uuid), info: asset }); // Resolve the promise once the asset is loaded
                } else {
                    assetManager.loadAny(asset, options, (loaded, total, item) => {
                        ResourceMap.log(`[ResourceMap] loadAny uuid: ${item.uuid}, path: ${item.url}, bundle: ${item['config'].name}, type: ${js.getClassName(item?.info?.['ctor'])}`);
                    }, (err, data) => {
                        loaded++;
                        if (onProgress) {
                            onProgress(loaded, total); // Forward progress during preload phase
                        }
                        if (err) {
                            ResourceMap.error(`[ResourceMap] loadAny err`, err);
                            resolve(null); // Resolve with null in case of an error
                            return;
                        }
                        resolve({ asset: data, info: asset }); // Resolve the promise once the asset is loaded
                    });
                }
            });
        });

        try {
            let data = await Promise.all(assetLoadingPromises);
            data = data.filter(result => result !== null);
            let results = [];
            data.forEach((v) => {
                let a = v.asset;
                if (Array.isArray(a)) {
                    a.forEach((_v) => {
                        results.push(_v);
                        this.updateUUIDMap(_v);
                    });
                } else {
                    results.push(a);
                    this.updateUUIDMap(a);
                }
            });

            if (onComplete) {
                onComplete(null, results); // Complete callback after loading
            }
            return results;
        } catch (err) {
            ResourceMap.error(`[ResourceMap] loadAny An error occurred during parallel asset loading:`, err);
            if (onComplete) {
                onComplete(err, null);
            }
        }
    }

Questions:

  1. Has anyone experienced similar issues when loading assets from many remote bundles on iOS?

  2. Could this be due to iOS memory limitations (low RAM or webview/browser constraints)?

  3. Are there any optimizations for loading/unloading assets to avoid reloads/crashes?

  4. How should I reconsider dividing bundles for a project with many mini games?

Any tips, thoughts, or just pointing me in the right direction would mean a lot. Thanks in advance!

Of course it could be related, so you could just test and debug, just try to load 5, 10, 15, etc amount of bundles and see when crash caused.

1 Like

Thanks for your suggestion! I tested it, and the issue seems to happen during the asset bundle loading process. While it’s loading, on mobile web platforms the browser automatically reloads, and on native apps, it crashes.

check you RAM web, maybe it’s so big and crash, u can scale down size image