Tổng hợp vấn đề với Unity.

Tổng hợp các vấn đề và cách giải quyết gặp phải trong quá trình phát triển game với Unity.

Build Problems

Không tăng Bundle Version Code khi build Android

Bundle Version Code là gì?

Bundle Version Code (BVC) là một số nguyên sử dụng để xác định phiên bản của ứng dụng. Số này không hiển thị cho người dùng nhưng rất quan trọng với Google Play Store và thiết bị Android để quản lý việc cập nhật ứng dụng.

Khác với Version (version name) là một string để hiển thị cho người, mô tả về phiên bản ứng dụng.

Đặc điểm chính

Là một số nguyên (0, 1, 2, 101...) được Unity khuyến nghị nên nhỏ hơn 100000 để buildApkPerCpuArchitecture có thể tạo ra version code hợp lệ.

Không hiển thị với người dùng.

Quan trọng cho việc cập nhật.

Vì sao cần tăng Bundle Version Code?

Như đã nói ở trên BVC được Google Play Store và Android sử dụng để xác định số phiên bản. Nên không thể cài đè một phiên bản có BVC nhỏ hơn phiên bản hiện tại hoặc trên Google Play Store, Google không chấp nhận việc cập nhật nếu bạn tải lên một phiên bản có BVC nhỏ hơn hoặc bằng phiên bản hiện tại.

Quy ước đánh số Bundle Version Code.

Dựa theo khuyến nghị của Unity, quy ước Semantic versioning ta có thể chia BVC thành 3 phần mỗi phần tương ứng với 2 chữ số tương ứng với MAJOR.MINOR.PATCH

Từ đó ta có công thức như sau bundleVersionCode = MAJOR*10000 + MINOR*100 + PATCH

Giải pháp hạn chế quên tăng Bundle Version Code!

Viết một script triển khai interface IPreprocessBuildWithReport để tự động tính BVC theo công thức trên.

Tạo một của sổ Build Tools mới bằng EditorWindow để hiển thị các thông tin thường xuyên cần chỉnh sửa như Icon, BVC...

Hoặc kết hợp cả 2 cách trên.

Game Development Problems

Các vấn đề gặp phải trong quá trình phát triển game với Unity

Game Development Problems

Các khớp bị cắt khi sử dụng Spine Animation.

Vấn đề

Lý do

Giải pháp

Game Development Problems

Không thể using một namespace.

Vấn đề

Trường hợp cụ thể

Lý do

Giải pháp

Game Development Problems

Copy một List

Vấn đề:

Nguyên nhân:

Giải pháp

Game Development Problems

Release sai cách khi sử dụng Addressables

Vấn đề.

Release sai cách khi sử dụng Addressables

Case 1: Early-Release. Với những assets cần sử dụng nhiều lần. Việc Release ngay khi load xong khiến cho mỗi lần cần sử dụng. Asset sẽ phải load từ ổ cứng lên.

public async UniTask<ICharacter> CreateCharacter(CharacterSheet.Row characterData)
{
    var handle = Addressables.LoadAssetAsync<GameObject>(characterData.PrefabAddr);
    await handle.Task;

    GameObject characterObj = resolver.Instantiate(handle.Result);

    handle.Release();
    return characterObj.GetComponent<ICharacter>();
}

Case 2: Cache chưa chính xác. Trong trường hơp này handle.Result đã được cache vào Dictionary nhưng handle lại bị release ngay sau đó. Tiềm ẩn vấn đề Value này sẽ được tham chiếu đến một "zombie object" gây ra lỗi NullReferenceException hoặc ArgumentNullException

private Dictionary<string, GameObject> projectileCaches = new();

public async UniTask<IProjectile> CreateProjectile(ProjectileSheet.Row projectileData)
{
    if (!projectileCaches.TryGetValue(projectileData.Id, out var projectilePrefab))
    {
        var handle = Addressables.LoadAssetAsync<GameObject>(projectileData.PrefabAddr);
        await handle.Task;

        projectileCaches.TryAdd(projectileData.Id, handle.Result);
        projectilePrefab = handle.Result;

        handle.Release();

        DebugExtension.Log("Load from disk!!!", Color.red);
    }

    DebugExtension.Log("Load from cache!!!", Color.green);
    GameObject projectileObj = resolver.Instantiate(projectilePrefab);
    return projectileObj.GetComponent<IProjectile>();
}

Cơ chế đếm tham chiếu của Addressables

Addressables không hoạt động theo kiểu bật/tắt đơn giản mà sử dụng một cơ chế thông minh gọi là Reference Counting.

Mỗi khi asset được load lên RAM bộ đếm tham chiếu sẽ tăng lên. Và ngược lại mỗi khi release bộ đếm tham chiếu sẽ giảm đi. Asset sẽ chỉ được unload khỏi ram khi ref-count trở về 0.

Ví dụ

A.cs gọi handleA = LoadAssetAsync(mySprite)

B.cs gọi handleA = LoadAssetAsync(mySprite)

A.cs gọi handleA.Release()

Lúc này, nếu có C.cs gọi handleC = LoadAssetAsync(mySprite) thì

Hoặc nếu B.cs gọi handleB.Release() thì

Tiếp theo, nếu có bất kỳ scripts nào gọi gọi LoadAssetAsync(mySprite) thì mySprite sẽ được tải lại từ ổ cứng.

Giải pháp

Với những object chỉ cần sử dụng một lần. Hoàn toàn có thể release ngay sau khi load.

Với những object sử dụng nhiều lần. Có thể sử dụng Addressables.InstantiateAsync() hoặc cache handle để có thể release khi không còn sử dụng đến nữa.

// Cache handles
public class ProjectileFactory
{
    private Dictionary<string, AsyncOperationHandle<GameObject>> loadedPrefabs = new();

    public async UniTask PreloadProjectiles(List<ProjectileSheet.Row> allProjectileData)
    {
        foreach (var data in allProjectileData)
        {
            if (!loadedPrefabs.ContainsKey(data.Id))
            {
                var handle = Addressables.LoadAssetAsync<GameObject>(data.PrefabAddr);
                loadedPrefabs.Add(data.Id, handle);
            }
        }

        await UniTask.WhenAll(loadedPrefabs.Values.Select(h => h.AsUniTask()));
    }

    public IProjectile CreateProjectile(string projectileId)
    {
        if (loadedPrefabs.TryGetValue(projectileId, out var handle))
        {
            GameObject projectileObj = resolver.Instantiate(handle.Result);
            return projectileObj.GetComponent<IProjectile>();
        }
        return null;
    }
    
    public void UnloadAll()
    {
        foreach(var handle in loadedPrefabs.Values) Addressables.Release(handle);
        loadedPrefabs.Clear();
    }
}

Release Problems

Vấn đề khi build release dự án Unity

Release Problems

Build iOS thành công nhưng không có file .xcworkspace

Vấn đề

Nguyên nhân

Giải pháp

  1. Sử dụng terminal cd tới folder build iOS (VD: cd /Users/admin/Unity/Gang2022/Builds/558/iOS)
  2. Chạy lệnh pod install để build lại file .xcworkspace
  3. Đọc, kiểm tra lỗi và tiếp tục xử lý
    • Lỗi AppLovinMediationGoogleAdapter không tương thích với Google-Mobile-Ads-SDK => Sửa phiên bản Google-Mobile-Ads-SDK trong file Podfile
    [!] CocoaPods could not find compatible versions for pod "Google-Mobile-Ads-SDK":
      In Podfile:
        AppLovinMediationGoogleAdapter (= 12.5.0.0) was resolved to 12.5.0.0, which depends on
          Google-Mobile-Ads-SDK (= 12.5.0)
    
        Google-Mobile-Ads-SDK (~> 11.13.0)
    
    Specs satisfying the `Google-Mobile-Ads-SDK (~> 11.13.0), Google-Mobile-Ads-SDK (= 12.5.0)` dependency were found, but they required a higher minimum deployment target.
    • Lỗi AppLovinMediationMyTargetAdapter yêu cầu phiên bản iOS tối thiểu cao hơn => trong Podfile sửa dòng platform :ios, 'iOS_version' hoặc thay đổi Target minimum iOS Version trong Player Settings
    [!] CocoaPods could not find compatible versions for pod "AppLovinMediationMyTargetAdapter":
    
      In Podfile:
        AppLovinMediationMyTargetAdapter (= 5.30.0.0)
    
    
    Specs satisfying the `AppLovinMediationMyTargetAdapter (= 5.30.0.0)` dependency were found, but they required a higher minimum deployment target.


  4. Nếu không còn lỗi và đã có file .xcworkspace thì có thể thực hiện archive trên file .xcworkspace này

Lưu ý

pod cache clean --all
rm -rf ~/Library/Caches/CocoaPods
rm -rf Pods
rm -f Podfile.lock
Release Problems

Tích hợp FacebookSDK - Open SSL not found

Vấn đề

image.png

image.png

Nguyên nhân

Do chưa cài đặt môi trường SSL và Java

Giải pháp

OpenSSL not found
  1. Download and install OpenSSL.
    Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions
    Win32 OpenSSL v#.#.# (not Light)
    OR Win64 OpenSSL v#.#.# (not Light)
  2. Add the OpenSSL directory to your path.
    Go to: Control Panel → System → Advanced system settings → Environment Variables
    Select the Variable Path in the “System variables” window and click Edit.
  3. Add the path to your OpenSSL bin folder to the end of the “Variable value” text. e.g. I added ;C:\Program Files\OpenSSL-Win64\bin to the end of the value text.
    → Take note, do not forget to add semi-colon ; before the C:/
  4. Restart computer.
Keytool not found
Release Problems

Lỗi Undefined symbol khi build iOS

Vấn đề

Khi build iOS vẫn thành công. Có file .xcworkspace nhưng khi Archive lại gặp rất nhiều lỗi Undefined symbol như hình dưới.

image.png

Nguyên nhân

Do các thư viện GoogleMobileAds, YandexMobileAds.... chưa được nhúng vào project.

Giải pháp

Thêm thủ công vào .xcworkspace

Trong của sổ làm việc của XCode chọn project Unity-iPhone > Targets Unity-iPhone > General > Frameworks, Libraries, and Embedded Content

Nhấn + để thêm các thư viện còn thiếu. Ở trường hợp trên là GoogleMobileAds.xcframework và YandexMobileAds.xcframework.

image.png

Cách khác (không biết gọi là gì =)))))

Với XCode 26.5 khi thêm thủ công file .xcframework có thể sẽ gặp lỗi sau
image.png

Lỗi này xảy ra với file YandexMobileAds.xcframework được tải trên internet.

Với trường hợp này chúng ta sẽ không thêm thủ công GoogleMobileAds.xcframework và YandexMobileAds.xcframework nữa. Giữ Frameworks, Libraries, and Embedded Content như ban đầu.

Trên thanh menu bên trái của Xcode, mở folder Project > Unity-iPhone > Frameworks.
- Nếu bạn thấy GoogleMobileAds và YandexMobileAds màu đỏ như hình thì chuột phải > Delete > Remove Reference
- Nếu không thì thôi :)))))
image.png

Giờ sang phần Target > Build Settings > tìm "Framework Search Paths" > Nháy đúp vào <Multiple value> và thêm 2 dòng lệnh sau
- $(SRCROOT)/Pods/YandexMobileAds
- $(SRCROOT)/Pods/Google-Mobile-Ads-SDK
Đây là biến môi trường tự động trỏ đúng vào thư mục project của bạn.
Nhìn sang bên cạnh nếu thấy non-recursive thì nhớ chuyển nó thành recursive. Để báo cho XCode biết cần phải đi tìm file .xcframework trong các thư mục con.
image.png

Tiếp tục, vẫn ở Build Settings, tìm "Other Linker Flags", nháy đúp vào và thêm lần lượt 4 dòng sau vào cuối.
-framework
YandexMobileAds
-framework
GoogleMobileAds
image.png

Xong rồi, giờ build thôi :>
À quên, nhớ Clean Build Folder trước khi build nhé.

Lưu ý

Framework được thêm vào nên có màu xanh (hoặc vàng) nhạt. Nếu màu đậm khả năng cao sẽ gặp lỗi

image.png

Nếu gặp lỗi như trên có thể chọn framework từ một dự án khác đã Archive thành công để thêm vào.

Nếu không có dự án cũ thì có thể tìm và tải file .xcframework trừ internet.



Release Problems

Tích hợp FacebookSDK - Lỗi khi Archive trong XCode

Vấn đề

Dự án Unity có tích hợp FacebookSDK. Build iOS thành công nhưng khi Archive trong XCode lại gặp lỗi như hình.

image.png

Nguyên nhân

Do xung đột phiên bản FacebookSDK trong Unity và trong XCode

Hoặc, do lỗi của phiên bản FacebookSDK

Giải pháp

Kiểm tra xem phiên bản FacebookSDK trong Unity và trong Podfile (cùng thư mục với file .xcworkspace) có trùng nhau chưa. Nếu chưa hãy update lại FacebookSDK trong Unity rồi build lại.

Nếu đã trùng nhau nhưng vẫn gặp lỗi. Vấn đề khẳ năng cao là do phiên bản FacebookSDK. Tại đây có 2 cách giải quyết: