{"id":13407090,"url":"https://github.com/icerockdev/moko-resources","last_synced_at":"2025-05-14T04:08:03.522Z","repository":{"id":37547791,"uuid":"204874263","full_name":"icerockdev/moko-resources","owner":"icerockdev","description":"Resources access for mobile (android \u0026 ios) Kotlin Multiplatform development","archived":false,"fork":false,"pushed_at":"2025-02-03T04:34:31.000Z","size":4304,"stargazers_count":1201,"open_issues_count":158,"forks_count":125,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-05-07T05:04:01.417Z","etag":null,"topics":["android","gradle-plugin","ios","kotlin","kotlin-multiplatform","kotlin-multiplatform-mobile","kotlin-native","moko"],"latest_commit_sha":null,"homepage":"https://moko.icerock.dev/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/icerockdev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-08-28T07:31:58.000Z","updated_at":"2025-05-06T22:29:01.000Z","dependencies_parsed_at":"2023-12-21T06:50:31.496Z","dependency_job_id":"fc593405-3ef3-4793-874f-357403d79e05","html_url":"https://github.com/icerockdev/moko-resources","commit_stats":{"total_commits":580,"total_committers":27,"mean_commits":21.48148148148148,"dds":0.4413793103448276,"last_synced_commit":"df157ee999b787bf0d3628ab33747ce51b56286d"},"previous_names":[],"tags_count":67,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icerockdev%2Fmoko-resources","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icerockdev%2Fmoko-resources/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icerockdev%2Fmoko-resources/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icerockdev%2Fmoko-resources/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/icerockdev","download_url":"https://codeload.github.com/icerockdev/moko-resources/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254069481,"owners_count":22009557,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","gradle-plugin","ios","kotlin","kotlin-multiplatform","kotlin-multiplatform-mobile","kotlin-native","moko"],"created_at":"2024-07-30T20:00:19.542Z","updated_at":"2025-05-14T04:07:58.505Z","avatar_url":"https://github.com/icerockdev.png","language":"Kotlin","readme":"![moko-resources](img/logo.png)  \n[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0) [![Download](https://img.shields.io/maven-central/v/dev.icerock.moko/resources) ](https://repo1.maven.org/maven2/dev/icerock/moko/resources) ![kotlin-version](https://kotlin-version.aws.icerock.dev/kotlin-version?group=dev.icerock.moko\u0026name=resources)\n![badge][badge-android]\n![badge][badge-iosX64]\n![badge][badge-iosArm64]\n![badge][badge-iosSimulatorArm64]\n![badge][badge-macosArm64]\n![badge][badge-macosX64]\n![badge][badge-jvm]\n![badge][badge-js]\n\n# Mobile Kotlin resources\n\nThis is a Kotlin MultiPlatform library (and Gradle plugin) that provides access to the resources on\nmacOS, iOS, Android the JVM and JS/Browser with the support of the default system localization.\n\nAlso MOKO resources\nsupports [Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform) so you can\nimplement all your UI in Kotlin with Jetpack Compose and MOKO resources.\n\n## Table of Contents\n\n- [Features](#features)\n- [Requirements](#requirements)\n- [Versions](#versions)\n- [Installation](#installation)\n- [Usage](#usage)\n- [Samples](#samples)\n- [Set Up Locally](#set-up-locally)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Features\n\n- **Strings, Plurals** to access the corresponding resources from common code;\n- **Colors** with light/dark mode support;\n- **Compose Multiplatform** support;\n- **Images** support (`svg`, `png`, `jpg`) with light/dark mode support;\n- **Fonts** support (`ttf`, `otf`);\n- **Files** support (as `raw` or `assets` for android);\n- **StringDesc** for lifecycle-aware access to resources and unified localization on both platforms;\n- **Static** iOS frameworks support;\n- **Fat and XC** frameworks support.\n\n## Requirements\n\n- Gradle version 7.5+\n- Kotlin 1.9.20+\n- Android Gradle Plugin 7.4.2+\n- Android API 16+\n- iOS version 11.0+\n- Compose Multiplatform 1.6.0+\n\n## Installation\n\n### Gradle setup\n\nroot build.gradle\n\n```groovy\nbuildscript {\n    repositories {\n        gradlePluginPortal()\n    }\n\n    dependencies {\n        classpath \"dev.icerock.moko:resources-generator:0.24.5\"\n    }\n}\n\n\nallprojects {\n    repositories {\n        mavenCentral()\n    }\n}\n```\n\nproject build.gradle\n\n```groovy\napply plugin: \"dev.icerock.mobile.multiplatform-resources\"\n\ndependencies {\n    commonMainApi(\"dev.icerock.moko:resources:0.24.5\")\n    commonMainApi(\"dev.icerock.moko:resources-compose:0.24.5\") // for compose multiplatform\n\n    commonTestImplementation(\"dev.icerock.moko:resources-test:0.24.5\")\n}\n\nmultiplatformResources {\n    resourcesPackage.set(\"org.example.library\") // required\n    resourcesClassName.set(\"SharedRes\") // optional, default MR\n    resourcesVisibility.set(MRVisibility.Internal) // optional, default Public\n    iosBaseLocalizationRegion.set(\"en\") // optional, default \"en\"\n    iosMinimalDeploymentTarget.set(\"11.0\") // optional, default \"9.0\"\n}\n```\n\n#### Custom resource sourceSet\n\nIf you need custom path for source of resources, you need add in plugin configuration resourcesSourceSets option:\nproject build.gradle\n\n```groovy\nmultiplatformResources {\n    resourcesPackage.set(\"org.example.library.customResource\") // required\n    resourcesSourceSets {\n        getByName(\"jvmMain\").srcDirs(\n            File(projectDir, \"customResources\")\n        )\n    }  \n}\n```\n\nOn next step, you must create inside of project directory folder with name: `customResources`, and moved your resources there. \n\n```\n- projectDirectory\n-- customResources\n--- assets\n--- base\n--- image\n```\n\nExample of custom sourceSet in: `resources-gallery` sample, inside `jvm-app`\n\n#### Export classes to Swift\n\nTo use `toUIColor()`, `toUIImage()`, `desc()` and other iOS extensions from Swift - you\nshould [add `export` declarations](https://kotlinlang.org/docs/multiplatform-build-native-binaries.html#export-dependencies-to-binaries):\n\n```\nframework {\n    export(\"dev.icerock.moko:resources:0.24.5\")\n    export(\"dev.icerock.moko:graphics:0.9.0\") // toUIColor here\n}\n```\n\n#### Multi-module Gradle projects\n\nIf you have multiple gradle modules and resources stored not in module that compiles into framework for iOS, for example:\n```\n- shared\n-- resources\n-- feature-1\n-- feature-2\n```\nYou should enable moko-resources gradle plugin in `resources` module, that contains resources, AND in `shared` module, that compiles into framework for iOS (same for jvm, JS, macos targets. Only android will works without this).\n\n### Xcode setup\n\nFor correct work of plugin tasks you need disable `ENABLE_USER_SCRIPT_SANDBOXING` in .xcodeproj file:\nXcode \u003e Build Settings \u003e Build Options \u003e User Script Sandbox set `NO` \n\nIn iOS/macOS Info.plist need to add localizations, to use localizations strings.\n\n```xml\n\n\u003ckey\u003eCFBundleLocalizations\u003c/key\u003e\u003carray\u003e\n\u003cstring\u003een\u003c/string\u003e\n\u003cstring\u003eru\u003c/string\u003e\n\u003c/array\u003e\n```\n\nin array should be added all used languages.\n\n### Android build types\n\nIf your project includes a build type, for example `staging` which isn't in moko-resources. That\nisn't an issue. Use matchingFallbacks to specify alternative matches for a given build type, as\nshown below\n\n```\nbuildTypes {\n    staging {\n        initWith debug\n        matchingFallbacks = ['debug']\n    }\n}\n```\n\n### JS Webpack\n\nJS/Browser generates json files which is included in webpack by default.\nFor more details about JS see `samples/resources-gallery/web-app` sample\n\n### iOS/macOS static kotlin frameworks support\n\nStatic framework can't have own resources, so we should setup additional `Build Phase` in Xcode\nthat will copy resources to application. \n\n\u003e **⚠ Warning**  \n\u003e \n\u003e This phase should be placed after Kotlin Framework Compilation phase.\n\nPlease replace `:yourframeworkproject` to kotlin project gradle path, and set correct relative\npath (`$SRCROOT/../` in example).\n\n#### With org.jetbrains.kotlin.native.cocoapods\n\nIn Xcode add `Build Phase` (at end of list) with script:\n\n```shell script\n\"$SRCROOT/../gradlew\" -p \"$SRCROOT/../\" :yourframeworkproject:copy`YourFrameworkName`FrameworkResourcesToApp \\\n    -Pmoko.resources.BUILT_PRODUCTS_DIR=\"$BUILT_PRODUCTS_DIR\" \\\n    -Pmoko.resources.CONTENTS_FOLDER_PATH=\"$CONTENTS_FOLDER_PATH\" \\\n    -Pkotlin.native.cocoapods.platform=\"$PLATFORM_NAME\" \\\n    -Pkotlin.native.cocoapods.archs=\"$ARCHS\" \\\n    -Pkotlin.native.cocoapods.configuration=\"$CONFIGURATION\" \n```\n\n`YourFrameworkName` is name of your project framework. Please, see on a static framework warning for get correct task name.\n\n#### Without org.jetbrains.kotlin.native.cocoapods\n\nIn Xcode add `Build Phase` (at end of list) with script:\n\n```shell script\n\"$SRCROOT/../gradlew\" -p \"$SRCROOT/../\" :yourframeworkproject:copyFrameworkResourcesToApp \\\n    -Pmoko.resources.PLATFORM_NAME=\"$PLATFORM_NAME\" \\\n    -Pmoko.resources.CONFIGURATION=\"$CONFIGURATION\" \\\n    -Pmoko.resources.ARCHS=\"$ARCHS\" \\\n    -Pmoko.resources.BUILT_PRODUCTS_DIR=\"$BUILT_PRODUCTS_DIR\" \\\n    -Pmoko.resources.CONTENTS_FOLDER_PATH=\"$CONTENTS_FOLDER_PATH\" \n```\n\n#### Disable warning about static framework usage\n\nTo disable warnings about static framework in gradle.properties:\n\n```xml\nmoko.resources.disableStaticFrameworkWarning=true\n```\n\n### iOS executable\n\nWhen you use `executable` kotlin target you should add custom build phase to xcode, after kotlin\ncompilation:\n\n```shell\n\"$SRCROOT/../gradlew\" -p \"$SRCROOT/../\" :shared:copyResourcesDebugExecutableIosSimulatorArm64 \\\n    -Pmoko.resources.BUILT_PRODUCTS_DIR=$BUILT_PRODUCTS_DIR \\\n    -Pmoko.resources.CONTENTS_FOLDER_PATH=$CONTENTS_FOLDER_PATH\n```\n\n`copyResourcesDebugExecutableIosSimulatorArm64` should be configured depends on target.\n\nConfigured sample you can see in `samples/kotlin-ios-app`\n\n### Creating Fat Framework with resources\n\nJust\nuse `FatFrameworkTask` [from kotlin plugin](https://kotlinlang.org/docs/mpp-build-native-binaries.html#build-universal-frameworks)\n.\n\n### Creating XCFramework with resources\n\nJust\nuse `XCFramework` [from kotlin plugin](https://kotlinlang.org/docs/mpp-build-native-binaries.html#build-xcframeworks)\n.\n\nBut if you use **static frameworks** required additional setup - add to Xcode build phase (at end):\n\n```bash\n\"$SRCROOT/../gradlew\" -p \"$SRCROOT/../\" :shared:copyResourcesMultiPlatformLibraryReleaseXCFrameworkToApp \\\n    -Pmoko.resources.BUILT_PRODUCTS_DIR=$BUILT_PRODUCTS_DIR \\\n    -Pmoko.resources.CONTENTS_FOLDER_PATH=$CONTENTS_FOLDER_PATH\n```\n\nand add in your build.gradle config:\n```kotlin\nmultiplatformResources {\n    configureCopyXCFrameworkResources(\"MultiPlatformLibrary\")\n}\n```\n\nreplace \"MultiPlatformLibrary\" with name that you use in `XCFramework` creation.\n\nDetails you can check in sample `samples/ios-static-xcframework`.\n\n## Usage\n\n### Example 1 - simple localization string\n\nThe first step is a create a file `strings.xml` in `commonMain/moko-resources/base` with the following\ncontent:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\" ?\u003e\n\u003cresources\u003e\n    \u003cstring name=\"my_string\"\u003eMy default localization string\u003c/string\u003e\n\u003c/resources\u003e\n```\n\nNext - create a file `strings.xml` with localized strings\nin `commonMain/moko-resources/\u003clanguageCode\u003e`. Here's an example of\ncreating `commonMain/moko-resources/ru` for a Russian localization:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\" ?\u003e\n\u003cresources\u003e\n    \u003cstring name=\"my_string\"\u003eМоя строка локализации по умолчанию\u003c/string\u003e\n\u003c/resources\u003e\n```\n\nAfter adding the resources we can call a gradle sync or execute a gradle\ntask `generateMRcommonMain`. This will generate a `MR` class containing `MR.strings.my_string`,\nwhich we can use in `commonMain`:\n\n```kotlin\nfun getMyString(): StringDesc {\n    return StringDesc.Resource(MR.strings.my_string)\n}\n``` \n\nAfter this we can use our functions on the platform side:  \nAndroid:\n\n```kotlin\nval string = getMyString().toString(context = this)\n```\n\niOS:\n\n```swift\nlet string = getMyString().localized()\n```\n\nJS:\n\n```kotlin\nval strings = MR.stringsLoader.getOrLoad() // loading localization from a remote file\nval string = getMyString().localized(strings)\n```\n\nNote: `StringDesc` is a multiple-source container for Strings: in StringDesc we can use a resource,\nplurals, formatted variants, or raw string. To convert `StringDesc` to `String` on Android\ncall `toString(context)` (a context is required for the resources usage), on iOS -\ncall `localized()`.\n\n#### Compose Multiplatform\n\nwith compose you can just call in `commonMain`\n\n```kotlin\nval string: String = stringResource(MR.strings.my_string)\n```\n\n#### MR directly from native side\n\nAndroid:\n\n```kotlin\nval string = MR.strings.my_string.desc().toString(context = this)\n``` \n\niOS:\n\n```swift\nlet string = MR.strings().my_string.desc().localized()\n```\n\n#### Get resourceId for Jetpack Compose / SwiftUI\n\nAndroid:\n\n```kotlin\nval resId = MR.strings.my_string.resourceId\n```\n\nfor example in Compose:\n\n```kotlin\ntext = stringResource(id = MR.strings.email.resourceId)\n```\n\niOS SwiftUI:\n\n```swift\nlet resource = MR.strings().email\nText(\n    LocalizedStringKey(resource.resourceId),\n    bundle: resource.bundle\n)\n```\n\nNote: more info in issue [#126](https://github.com/icerockdev/moko-resources/issues/126).\n\n### Example 2 - formatted localization string\n\nIn `commonMain/moko-resources/base/strings.xml` add:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\" ?\u003e\n\u003cresources\u003e\n    \u003cstring name=\"my_string_formatted\"\u003eMy format \\'%s\\'\u003c/string\u003e\n\u003c/resources\u003e\n```\n\nThen add the localized values for other languages like in example #1.\nNow create the following function in `commonMain`:\n\n```kotlin\nfun getMyFormatDesc(input: String): StringDesc {\n    return StringDesc.ResourceFormatted(MR.strings.my_string_formatted, input)\n}\n```\n\nTo create formatted strings from resources you can also use extension `format`:\n\n```kotlin\nfun getMyFormatDesc(input: String): StringDesc {\n    return MR.strings.my_string_formatted.format(input)\n}\n```\n\nNow add support on the platform side like in example #1:  \nAndroid:\n\n```kotlin\nval string = getMyFormatDesc(\"hello\").toString(context = this)\n```\n\niOS:\n\n```swift\nlet string = getMyFormatDesc(input: \"hello\").localized()\n```\n\nWarning: Do no mix positioned placeholders with unpositioned ones within a string, as this may lead\nto\ndifferent behaviour on different platforms. Stick to one style for each string.\n\n### Example 3 - plural string\n\nThe first step is to create a file `plurals.xml` in `commonMain/moko-resources/base` with the\nfollowing content:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\" ?\u003e\n\u003cresources\u003e\n    \u003cplural name=\"my_plural\"\u003e\n        \u003citem quantity=\"zero\"\u003ezero\u003c/item\u003e\n        \u003citem quantity=\"one\"\u003eone\u003c/item\u003e\n        \u003citem quantity=\"two\"\u003etwo\u003c/item\u003e\n        \u003citem quantity=\"few\"\u003efew\u003c/item\u003e\n        \u003citem quantity=\"many\"\u003emany\u003c/item\u003e\n        \u003citem quantity=\"other\"\u003eother\u003c/item\u003e\n    \u003c/plural\u003e\n\u003c/resources\u003e\n```\n\nThen add the localized values for other languages like in example #1.  \nNext, create a function in `commonMain`:\n\n```kotlin\nfun getMyPluralDesc(quantity: Int): StringDesc {\n    return StringDesc.Plural(MR.plurals.my_plural, quantity)\n}\n```\n\nNow add support on the platform side like in example #1:  \nAndroid:\n\n```kotlin\nval string = getMyPluralDesc(10).toString(context = this)\n```\n\niOS:\n\n```swift\nlet string = getMyPluralDesc(quantity: 10).localized()\n```\n\n### Example 4 - plural formatted string\n\nThe first step is to create file `plurals.xml` in `commonMain/moko-resources/base` with the following\ncontent:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\" ?\u003e\n\u003cresources\u003e\n    \u003cplural name=\"my_plural\"\u003e\n        \u003citem quantity=\"zero\"\u003eno items\u003c/item\u003e\n        \u003citem quantity=\"one\"\u003e%d item\u003c/item\u003e\n        \u003citem quantity=\"two\"\u003e%d items\u003c/item\u003e\n        \u003citem quantity=\"few\"\u003e%d items\u003c/item\u003e\n        \u003citem quantity=\"many\"\u003e%d items\u003c/item\u003e\n        \u003citem quantity=\"other\"\u003e%d items\u003c/item\u003e\n    \u003c/plural\u003e\n\u003c/resources\u003e\n```\n\nThen add the localized values for other languages like in example #1.  \nNext, create a function in `commonMain`:\n\n```kotlin\nfun getMyPluralFormattedDesc(quantity: Int): StringDesc {\n    // we pass quantity as selector for correct plural string and for pass quantity as argument for formatting\n    return StringDesc.PluralFormatted(MR.plurals.my_plural, quantity, quantity)\n}\n```\n\nTo create formatted plural strings from resources you can also use extension `format`:\n\n```kotlin\nfun getMyPluralFormattedDesc(quantity: Int): StringDesc {\n    // we pass quantity as selector for correct plural string and for pass quantity as argument for formatting\n    return MR.plurals.my_plural.format(quantity, quantity)\n}\n```\n\nAnd like in example #1, add the platform-side support:  \nAndroid:\n\n```kotlin\nval string = getMyPluralFormattedDesc(10).toString(context = this)\n```\n\niOS:\n\n```swift\nlet string = getMyPluralFormattedDesc(quantity: 10).localized()\n```\n\nCompose:\n\nWith compose, you can simply use `pluralStringResource`\n\n```kotlin\nText(\n    text = pluralStringResource(\n        MR.plurals.runtime_format,\n        quantity,\n        quantity\n    )\n)\n```\n\n### Example 5 - pass raw string or resource\n\nIf we already use some resources as a placeholder value, we can use `StringDesc` to change the\nstring source:\n\n```kotlin\nfun getUserName(user: User?): StringDesc {\n    if (user != null) {\n        return StringDesc.Raw(user.name)\n    } else {\n        return StringDesc.Resource(MR.strings.name_placeholder)\n    }\n}\n```\n\nAnd just like in example 1 usage on platform side:  \nAndroid:\n\n```kotlin\nval string1 = getUserName(user).toString(context = this) // we got name from User model\nval string2 = getUserName(null).toString(context = this) // we got name_placeholder from resources\n```\n\niOS:\n\n```swift\nlet string1 = getUserName(user: user).localized() // we got name from User model\nlet string2 = getUserName(user: null).localized() // we got name_placeholder from resources\n```\n\n### Example 6 - Select localization in runtime\n\nYou can force `StringDesc` to use preferred localization in common code:\n\n```kotlin\nStringDesc.localeType = StringDesc.LocaleType.Custom(\"es\")\n```\n\nand return to system behaviour (when localization depends on device settings):\n\n```kotlin\nStringDesc.localeType = StringDesc.LocaleType.System\n```\n\nAndroid:\n\nAdd this to your app's `build.gradle` to keep all locales in resulting [App Bundle](https://www.youtube.com/watch?v=IPLhLu0kvYw\u0026ab_channel=AndroidDevelopers) if you want them all to be available in runtime (Otherwise, when the user downloads the app from PlayMarket, resources for his system locale only will be available).\n\n```\nandroid {\n    bundle {\n        language {\n            enableSplit = false\n        }\n    }\n}\n```\n\n### Example 7 - Shared Images\n\nPlace images in the `commonMain/moko-resources/images` directory. Nested directories are also supported.\n\n#### png and jpg\n\nImage names should end with one of:\n\n- `@0.75x` - android ldpi;\n- `@1x` - android mdpi, ios 1x;\n- `@1.5x` - android hdpi;\n- `@2x` - android xhdpi, ios 2x;\n- `@3x` - android xxhdpi, ios 3x;\n- `@4x` - android xxxhdpi.\n\nIf we add the following files to `commonMain/moko-resources/images`:\n\n- `home_black_18@1x.png`\n- `home_black_18@2x.png`\n\nThen we get an autogenerated `MR.images.home_black_18` `ImageResource` in code. Usage:\n\n- Android: `imageView.setImageResource(image.drawableResId)`\n- iOS: `imageView.image = image.toUIImage()`\n\n#### dark mode\n\nTo support Dark Mode images, you can add -dark and optionally -light to the name of an image. Make sure the rest of the name matches the corresponding light mode image:\n\n- `car.svg`\n- `car-dark.svg`\n\n#### svg\n\nThe Image generator also supports `svg` files.\n\nIf we add the following file to `commonMain/moko-resources/images`:\n\n- `car_black.svg`\n\nThen we get an autogenerated `MR.images.car_black` `ImageResource` in code. Usage:\n\n- Android: `imageView.setImageResource(image.drawableResId)`\n- iOS: `imageView.image = image.toUIImage()`\n\nOn Android it is a `VectorDrawable`,\n\nOn iOS iOS 13 or later it is a `UIImage` in the Assets catalog with `preserves-vector-representation` set to `true`.\n\n#### images by name\n\nYou can get images by their name, too.\n\nIn `commonMain` create a `Resources.kt` file with the content below.\n\n\n```kotlin\nfun getImageByFileName(name: String): ImageResource {\n    val fallbackImage = MR.images.transparent\n    return MR.images.getImageByFileName(name) ?: fallbackImage\n}\n```\n\nUsage: \n\n- Android: `imageView.setImageResource(getImageByFileName(\"image_name\"))`\n- iOS: `imageView.image = ResourcesKt.getImageByFileName(name: \"image_name\").toUIImage()!`\n\n#### Compose Multiplatform\n\nWith compose, you can simply use a `painterResource` in `commonMain`\n\n```kotlin\nval painter: Painter = painterResource(MR.images.home_black_18)\n```\n\n#### SwiftUI\n\nFor SwiftUI, create this `Image` extension:\n\n```swift\nextension Image {\n    init(resource: KeyPath\u003cMR.images, ImageResource\u003e) {\n        self.init(uiImage: MR.images()[keyPath: resource].toUIImage()!)\n    }\n}\n```\n\nThen, you can refer to `ImageResource`s directly by their key path, which provides compiler errors for typos or missing resources:\n\n```swift\nImage(resource: \\.home_black_18)\n```\n\n### Example 8 - pass font\n\nFonts resources directory is `commonMain/moko-resources/fonts`.\nSupported type of resources:\n- `ttf`\n- `otf`\n\nIf we add to `commonMain/moko-resources/fonts` files:\n- `Raleway-Bold.ttf`\n- `Raleway-Regular.otf`\n- `Raleway-Italic.ttf`\n\nWe got autogenerated:\n- `MR.fonts.raleway_italic`,\n- `MR.fonts.raleway_regular`,\n- `MR.fonts.raleway_bold_italic`\n\nin code, that we can use:\n\n- Android: `textView.typeface = font.getTypeface(context = this)`\n- iOS: `textView.font = font.uiFont(withSize: 14.0)`\n\n#### Compose Multiplatform\n\nwith compose you can just call in `commonMain`\n\n```kotlin\nval fontFamily: FontFamily = fontFamilyResource(MR.fonts.Raleway.italic)\n```\n\nor you can get `Font`\n\n```kotlin\nval font: Font = MR.fonts.Raleway.italic.asFont(\n  weight = FontWeight.Normal, // optional\n  style = FontStyle.Normal // optional\n)\n```\n#### SwiftUI\n\nFor SwiftUI, create this `Font` extension:\n\n```swift\nextension Font {\n    init(resource: KeyPath\u003cMR.fonts, FontResource\u003e, withSize: Double = 14.0) {\n        self.init(MR.fonts()[keyPath: resource].uiFont(withSize: withSize))\n    }\n}\n```\n\nThen, you can refer to `FontResource`s directly by their key path, which provides compiler errors for typos or missing resources:\n\n```swift\n Text(\"Text displayed resource font\")\n   .font(Font(resource: \\.raleway_regular, withSize: 14.0))\n```\n\n### Example 9 - pass colors\n\nColors resources directory is `commonMain/moko-resources/colors`.  \nColors files is `xml` with format:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003cresources\u003e\n    \u003c!-- format: #RRGGBB[AA] or 0xRRGGBB[AA] or RRGGBB[AA] where [AA] - optional --\u003e\n    \u003ccolor name=\"valueColor\"\u003e#B02743FF\u003c/color\u003e\n    \u003ccolor name=\"referenceColor\"\u003e@color/valueColor\u003c/color\u003e\n    \u003ccolor name=\"themedColor\"\u003e\n        \u003clight\u003e0xB92743FF\u003c/light\u003e\n        \u003cdark\u003e7CCFEEFF\u003c/dark\u003e\n    \u003c/color\u003e\n    \u003ccolor name=\"themedReferenceColor\"\u003e\n        \u003clight\u003e@color/valueColor\u003c/light\u003e\n        \u003cdark\u003e@color/referenceColor\u003c/dark\u003e\n    \u003c/color\u003e\n\u003c/resources\u003e\n```\n\nIf you want use one color without light/dark theme selection:\n\n```xml\n\n\u003ccolor name=\"valueColor\"\u003e#B02743FF\u003c/color\u003e\n```\n\nIf you want use value of other color - use references:\n\n```xml\n\n\u003ccolor name=\"referenceColor\"\u003e@color/valueColor\u003c/color\u003e\n```\n\nIf you want different colors in light/dark themes:\n\n```xml\n\n\u003ccolor name=\"themedColor\"\u003e\n    \u003clight\u003e0xB92743FF\u003c/light\u003e\n    \u003cdark\u003e7CCFEEFF\u003c/dark\u003e\n\u003c/color\u003e\n```\n\nAlso themed colors can be referenced too:\n\n```xml\n\n\u003ccolor name=\"themedReferenceColor\"\u003e\n    \u003clight\u003e@color/valueColor\u003c/light\u003e\n    \u003cdark\u003e@color/referenceColor\u003c/dark\u003e\n\u003c/color\u003e\n```\n\nColors available in common code insode `MR.colors.**` as `ColorResource`.  \n`ColorResource` can be read from platform side:\n\nandroid:\n\n```kotlin\nval color: Int = MR.colors.valueColor.getColor(context = this)\n```\n\niOS:\n\n```swift\nval color: UIColor = MR.colors.valueColor.getUIColor()\n```\n\nmacOS:\n\n```swift\nval color: NSColor = MR.colors.valueColor.getNSColor()\n```\n\njvm:\n\n```kotlin\nval light: Color = MR.colors.valueColor.lightColor\nval dark: Color = MR.colors.valueColor.darkColor\n```\n\nweb:\n\n```kotlin\nval light: Color = MR.colors.valueColor.lightColor\nval dark: Color = MR.colors.valueColor.darkColor\n```\n\n#### Compose Multiplatform\n\nwith compose you can just call in `commonMain`\n\n```kotlin\nval color: Color = colorResource(MR.colors.valueColor)\n```\n\n### Example 10 - plain file resource access\n\nThe first step is a create a resource file `test.txt` for example,\nin `commonMain/moko-resources/files`\nAfter gradle sync we can get file by id `MR.files.test`\nMoko-resources has out of box implementation function for read text files from common\ncode - `readText()`\n\nUsage on Android:\n\n```\nval text = MR.files.test.getText(context = this)\n```\n\nUsage on Apple:\n\n```\nval text = MR.files.test.readText()\n```\n\nIf you want to read files not as text, add your own implementation to expect/actual FileResource\n\n#### Compose Multiplatform\n\nwith compose you can just call in `commonMain`\n\n```kotlin\nval fileContent: String? by MR.files.test.readTextAsState()\n```\n\n### Example 11 - assets access\n\nAssets allow you save directories hierarchy (in files structure is plain). Locate files\nto `commonMain/moko-resources/assets` and access to it by `MR.assets.*`\n\n#### Compose Multiplatform\n\nwith compose you can just call in `commonMain`\n\n```kotlin\nval assetContent: String? by MR.assets.test.readTextAsState()\n```\n\n## Known issues\n\n### iOS shows key instead of localized text\n\n1. check that generated `Localizable.strings` file is valid - open it by Xcode (located in `shared/shared/build/bin/iosSimulatorArm64/debugFramework/shared.framework/\u003cproject-name\u003e:shared.bundle/Contents/Resources/Base.lproj/Localizable.strings` and in other `.lproj` directories. If Xcode show error in file - you should fix content of strings.xml (for example you use some special character that broke file).\n\n2. check that your generated `.bundle` exist inside application at runtime. In Xcode inside group `Products` select your application and click `Show in Finder`. Then click `Show Package Contents`. Inside `.app` you should see `.bundle` in root directory if you use static framework. And in `Frameworks/shared.framework` if you use dynamic framework. If `bundle` missed - check installation guide. Specifically xcode build phase part if you use static framework. And check that you apply moko-resources plugin in `shared` gradle module.\n\n3. check that your `strings.xml` contains all keys for language that you use. If you have keys `test1`, `test2` in `Base/strings.xml`, and only `test1` in `ru/strings.xml` then you got key instead of text in ru locale for `test2` key. iOS not fallback to base locale now\n\n## Samples\n\nIn `samples` directory you can find multiple projects showed different usages.\n\n- [resources-gallery](samples/resources-gallery) - android, iOS, macOS, jvm, web applications with\n  all resources types usage.\n- [compose-resources-gallery](samples/compose-resources-gallery) - android, iOS, jvm, web\n  Compose Multiplatform applications with all resources types usage.\n- [android-mpp-app](samples/android-mpp-app) - android application that configured as multiplatform\n  module.\n- [auto-manifest](samples/auto-manifest) - sample of\n  usage [auto-manifest](https://github.com/GradleUp/auto-manifest) plugin.\n- [compose-jvm-app](samples/compose-jvm-app) - Compose Desktop jvm application with resources usage.\n- [ios-static-xcframework](samples/ios-static-xcframework) - iOS application with static XCFramework\n  and resources.\n- [kotlin-ios-app](samples/kotlin-ios-app) - iOS application without swift - full code on kotlin,\n  with resources usage.\n\n## Set Up Locally\n\nIn root of repository contains `moko-resources` gradle project - libraries and gradle plugin. You\ncan just open project in IDE and develop. Then for tests in samples you should run\nrun `./gradlew publishToMavenLocal` gradle task. After this you can open any sample from `samples`\nin IDE and test your local version of `moko-resources`.\n\nTo check your changes before pull request run:\n```bash\n# check lib \u0026 plugin\n./local-check.sh\n# check samples\n./local-samples-check.sh\n```\n\n## Contributing\n\nAll development (both new features and bug fixes) is performed in the `develop` branch. This\nway `master` always contains the sources of the most recently released version. Please send PRs with\nbug fixes to the `develop` branch. Documentation fixes in the markdown files are an exception to\nthis rule. They are updated directly in `master`.\n\nThe `develop` branch is pushed to `master` on release.\n\nFor more details on contributing please see the [contributing guide](CONTRIBUTING.md).\n\n## License\n\n    Copyright 2019 IceRock MAG Inc.\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n    \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n\n[badge-android]: http://img.shields.io/badge/platform-android-6EDB8D.svg?style=flat\n\n[badge-ios]: http://img.shields.io/badge/platform-ios-CDCDCD.svg?style=flat\n\n[badge-js]: http://img.shields.io/badge/platform-js-F8DB5D.svg?style=flat\n\n[badge-jvm]: http://img.shields.io/badge/platform-jvm-DB413D.svg?style=flat\n\n[badge-linux]: http://img.shields.io/badge/platform-linux-2D3F6C.svg?style=flat\n\n[badge-windows]: http://img.shields.io/badge/platform-windows-4D76CD.svg?style=flat\n\n[badge-mac]: http://img.shields.io/badge/platform-macos-111111.svg?style=flat\n\n[badge-watchos]: http://img.shields.io/badge/platform-watchos-C0C0C0.svg?style=flat\n\n[badge-tvos]: http://img.shields.io/badge/platform-tvos-808080.svg?style=flat\n\n[badge-wasm]: https://img.shields.io/badge/platform-wasm-624FE8.svg?style=flat\n\n[badge-nodejs]: https://img.shields.io/badge/platform-nodejs-68a063.svg?style=flat\n\n[badge-iosX64]: https://img.shields.io/badge/platform-iosX64-CDCDCD?style=flat\n\n[badge-iosArm64]: https://img.shields.io/badge/platform-iosArm64-CDCDCD?style=flat\n\n[badge-iosSimulatorArm64]: https://img.shields.io/badge/platform-iosSimulatorArm64-CDCDCD?style=flat\n\n[badge-macosX64]: https://img.shields.io/badge/platform-macosX64-111111?style=flat\n\n[badge-macosArm64]: https://img.shields.io/badge/platform-macosArm64-111111?style=flat    \n","funding_links":[],"categories":["Libraries","Kotlin","Uncategorized"],"sub_categories":["🛢 Resources","Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficerockdev%2Fmoko-resources","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ficerockdev%2Fmoko-resources","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficerockdev%2Fmoko-resources/lists"}