moko-resources

repository·master·Indexed 23 days ago

https://github.com/icerockdev/moko-resources

A Kotlin Multiplatform library and Gradle plugin providing unified access to resources—including strings, images, fonts, and colors—across Android, iOS, macOS, JVM, and JS/Browser. It supports system localization, Compose Multiplatform, and provides a StringDesc abstraction for handling resources, plurals, and formatted strings in common code.

Tokens
7.5K
Snippets
17
Records
43
Agent score
79%

What's inside moko-resources

  1. How StringDesc works and how to use it

    master

    A StringDesc is a multi-source container for strings. It can represent a resource, a plural, a formatted variant, or a raw string. This abstraction allows you to write logic in commonMain that decides what string to show, while leaving the how to render it to the platform-specific code.

    Common Types of StringDesc:

    • StringDesc.Resource(MR.strings.key): A standard resource.
    • StringDesc.ResourceFormatted(MR.strings.key, arg): A resource with arguments.
    • StringDesc.Plural(MR.plurals.key, quantity): A plural resource.
    • StringDesc.Raw(string): A plain, non-resource string.

    Runtime Localization Control: You can force a specific locale in common code:

    • StringDesc.localeType = StringDesc.LocaleType.Custom("es") (e.g., for Spanish).
    • StringDesc.localeType = StringDesc.LocaleType.System (returns to device settings).
    // Example: Switching between a raw string and a resource
    fun getUserName(user: User?): StringDesc {
        return if (user != null) {
            StringDesc.Raw(user.name)
        } else {
            StringDesc.Resource(MR.strings.name_placeholder)
        }
    }
  2. Build the Kotlin 2.0 sample project

    master

    To build the sample project that demonstrates usage with Kotlin 2.0, you must first ensure the moko-resources library is available in your local Maven repository.

    1. Publish moko-resources to your local Maven repository by running ./gradlew publishToMavenLocal from the moko-resources root directory.
    2. Build the sample project using your IDE or by running ./gradlew build within the sample directory.
  3. Setup resources for iOS/macOS static Kotlin frameworks

    master

    Static frameworks cannot contain their own resources. You must add a custom Build Phase in Xcode (placed after the Kotlin Framework Compilation phase) to copy resources into the application.

    Choose the script based on whether you are using CocoaPods.

    # Using org.jetbrains.kotlin.native.cocoapods
    "$SRCROOT/../gradlew" -p "$SRCROOT/../" :yourframeworkproject:copy`YourFrameworkName`FrameworkResourcesToApp \ 
        -Pmoko.resources.BUILT_PRODUCTS_DIR="$BUILT_PRODUCTS_DIR" \ 
        -Pmoko.resources.CONTENTS_FOLDER_PATH="$CONTENTS_FOLDER_PATH" \ 
        -Pkotlin.native.cocoapods.platform="$PLATFORM_NAME" \ 
        -Pkotlin.native.cocoapods.archs="$ARCHS" \ 
        -Pkotlin.native.cocoapods.configuration="${KOTLIN_FRAMEWORK_BUILD_TYPE:-$CONFIGURATION}" 
    
    # Without org.jetbrains.kotlin.native.cocoapods
    "$SRCROOT/../gradlew" -p "$SRCROOT/../" :yourframeworkproject:copyFrameworkResourcesToApp \ 
        -Pmoko.resources.PLATFORM_NAME="$PLATFORM_NAME" \ 
        -Pmoko.resources.CONFIGURATION="${KOTLIN_FRAMEWORK_BUILD_TYPE:-$CONFIGURATION}" \ 
        -Pmoko.resources.ARCHS="$ARCHS" \ 
        -Pmoko.resources.BUILT_PRODUCTS_DIR="$BUILT_PRODUCTS_DIR" \ 
        -Pmoko.resources.CONTENTS_FOLDER_PATH="$CONTENTS_FOLDER_PATH" 
  4. Setup resources for iOS XCFrameworks

    master

    When using static frameworks with XCFrameworks, you must add an Xcode build phase at the end of the list and configure your build.gradle to handle the resource copying.

    # Xcode Build Phase
    "$SRCROOT/../gradlew" -p "$SRCROOT/../" :shared:copyResourcesMultiPlatformLibraryReleaseXCFrameworkToApp \ 
        -Pmoko.resources.BUILT_PRODUCTS_DIR=$BUILT_PRODUCTS_DIR \ 
        -Pmoko.resources.CONTENTS_FOLDER_PATH=$CONTENTS_FOLDER_PATH
    // build.gradle
    multiplatformResources {
        configureCopyXCFrameworkResources("MultiPlatformLibrary")
    }
  5. Configure Android Host Tests for moko-resources

    master

    To allow moko-resources to access generated R classes during unit testing, you must enable Android resources for host tests. The method depends on your Android Gradle Plugin (AGP) version.

    For AGP 8.8.0 and higher: Use the withHostTest DSL inside the androidLibrary block.

    For AGP 8.2.0 - 8.7.x: Use the legacy android block with testOptions.

    // AGP 8.8.0+
    kotlin {
        androidLibrary {
            withHostTest {
                isIncludeAndroidResources = true
            }
        }
    }
    
    // AGP 8.2.0 - 8.7.x
    android {
        testOptions {
            unitTests.isIncludeAndroidResources = true
        }
    }
  6. Install moko-resources via Gradle

    master

    To use moko-resources, you must configure both your root build.gradle and your project-level build.gradle. This involves applying the dev.icerock.mobile.multiplatform-resources plugin and adding the necessary dependencies for common code and Compose Multiplatform support.

    // root build.gradle
    buildscript {
        repositories {
            gradlePluginPortal()
        }
    
        dependencies {
            classpath "dev.icerock.moko:resources-generator:0.26.4"
        }
    }
    
    allprojects {
        repositories {
            mavenCentral()
        }
    }
    
    // project build.gradle
    apply plugin: "dev.icerock.mobile.multiplatform-resources"
    
    dependencies {
        commonMainApi("dev.icerock.moko:resources:0.26.4")
        commonMainApi("dev.icerock.moko:resources-compose:0.26.4") // for compose multiplatform
    
        commonTestImplementation("dev.icerock.moko:resources-test:0.26.4")
    }
    
    multiplatformResources {
        resourcesPackage.set("org.example.library") // required
        resourcesClassName.set("SharedRes") // optional, default MR
        resourcesVisibility.set(MRVisibility.Internal) // optional, default Public
        iosBaseLocalizationRegion.set("en") // optional, default "en"
        iosMinimalDeploymentTarget.set("11.0") // optional, default "9.0"
    }
  7. Export moko-resources to Swift

    master

    To access iOS extensions like toUIColor(), toUIImage(), and desc() from Swift code, you must explicitly export the moko-resources and graphics dependencies in your Kotlin framework configuration.

    framework {
        export("dev.icerock.moko:resources:0.26.4")
        export("dev.icerock.moko:graphics:0.10.0") // toUIColor here
    }
  8. Build the iOS XCFramework sample project

    master

    To build the sample project that demonstrates an XCFramework containing a static framework for iOS, follow these steps:

    1. Publish moko-resources locally: In the root directory of the moko-resources repository, run the Gradle task to publish the library to your local Maven repository.
    2. Build the sample: Navigate to the sample project and build it using your IDE or by running the Gradle build command.

    Note: This sample is specifically designed to show how to package an XCFramework with a static framework inside for iOS integration.

  9. Create and use plural localization strings

    master

    Plurals allow you to provide different string versions based on a numeric quantity.

    1. Define in XML: Create commonMain/moko-resources/base/plurals.xml. You must include items for various quantities (e.g., zero, one, other).
    2. Access in common code: Use StringDesc.Plural(MR.plurals.key, quantity) or the .format(quantity, ...) extension.

    Compose Multiplatform: Use pluralStringResource(MR.plurals.key, selector, ...args).

    Platform Usage:

    • Android: StringDesc.toString(context).
    • iOS: StringDesc.localized().
    <!-- commonMain/moko-resources/base/plurals.xml -->
    <resources>
        <plural name="my_plural">
            <item quantity="zero">zero</item>
            <item quantity="one">one</item>
            <item quantity="other">other</item>
        </plural>
    </resources>
    // commonMain
    fun getMyPluralDesc(quantity: Int): StringDesc {
        return StringDesc.Plural(MR.plurals.my_plural, quantity)
    }
    
    // Compose Multiplatform
    Text(text = pluralStringResource(MR.plurals.my_plural, quantity)) 
  10. Access plain file and asset resources

    master

    Moko-resources allows accessing raw files and assets.

    Plain Files:

    • Place files in commonMain/moko-resources/files.
    • Android: MR.files.key.getText(context).
    • Apple: MR.files.key.readText().
    • Compose Multiplatform: MR.files.key.readTextAsState().

    Assets:

    • Place files in commonMain/moko-resources/assets (supports directory hierarchy).
    • Compose Multiplatform: MR.assets.key.readTextAsState().