Skip to content

Commit

Permalink
#747 draft for NSBundle search by class
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex009 committed Nov 18, 2024
1 parent cec8905 commit 49f7518
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 4 deletions.
2 changes: 2 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ kotlin.code.style=official
kotlin.mpp.stability.nowarn=true
kotlin.mpp.androidGradlePluginCompatibility.nowarn=true
kotlin.mpp.androidSourceSetLayoutVersion=2
kotlin.mpp.applyDefaultHierarchyTemplate=false
kotlin.mpp.enableCInteropCommonization=true

org.jetbrains.compose.experimental.jscanvas.enabled=true
org.jetbrains.compose.experimental.uikit.enabled=true
Expand Down
2 changes: 1 addition & 1 deletion gradle/moko.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[versions]
resourcesVersion = "0.24.3"
resourcesVersion = "0.24.4"

[libraries]
resources = { module = "dev.icerock.moko:resources", version.ref = "resourcesVersion" }
Expand Down
16 changes: 16 additions & 0 deletions resources/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget

/*
* Copyright 2019 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/
Expand Down Expand Up @@ -25,6 +29,18 @@ kotlin {
}
}
}

// setup bundle searcher for apple
targets
.withType<KotlinNativeTarget>()
.matching { it.konanTarget.family.isAppleFamily }
.configureEach {
compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME) {
val appleNative by cinterops.creating {
defFile(project.file("src/appleMain/def/appleNative.def"))
}
}
}
}

android {
Expand Down
3 changes: 3 additions & 0 deletions resources/src/appleMain/def/appleNative.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://kotlinlang.org/docs/native-definition-file.html
language = Objective-C
package = dev.icerock.moko.resources.apple.native
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,32 @@

package dev.icerock.moko.resources.utils

import kotlinx.cinterop.BetaInteropApi
import kotlinx.cinterop.ObjCObjectBaseMeta
import platform.Foundation.NSBundle
import platform.Foundation.NSDirectoryEnumerator
import platform.Foundation.NSFileManager
import platform.Foundation.NSLog
import platform.Foundation.NSURL
import platform.Foundation.pathExtension
import kotlin.experimental.ExperimentalObjCName

@OptIn(ExperimentalObjCName::class, BetaInteropApi::class)
@ObjCName("ObjCAnchorClass")
internal object ObjCAnchorClass : ObjCObjectBaseMeta()

fun NSBundle.Companion.loadableBundle(identifier: String): NSBundle {
val bundlePath: String = NSBundle.mainBundle.bundlePath
val enumerator: NSDirectoryEnumerator = requireNotNull(NSFileManager.defaultManager.enumeratorAtPath(bundlePath))
// we should use search by our class because dynamic framework with resources can be placed in
// external directory, not inside app directory (NSBundle.main). for example in case of
// SwiftUI preview - app directory empty, but dynamic framework with resources will be in
// different directory (DerivedData)
@OptIn(BetaInteropApi::class)
val bundlePath: String = NSBundle.bundleForClass(ObjCAnchorClass).bundlePath

val enumerator: NSDirectoryEnumerator = requireNotNull(
NSFileManager.defaultManager.enumeratorAtPath(bundlePath)
) { "can't get enumerator" }

while (true) {
val relativePath: String = enumerator.nextObject() as? String ?: break
val url = NSURL(fileURLWithPath = relativePath)
Expand All @@ -22,7 +39,8 @@ fun NSBundle.Companion.loadableBundle(identifier: String): NSBundle {
val loadedIdentifier: String? = foundedBundle?.bundleIdentifier

if (isBundleSearchLogEnabled) {
println("moko-resources auto-load bundle with identifier $loadedIdentifier at path $fullPath")
// NSLog to see this logs in Console app when debug SwiftUI previews or release apps
NSLog("moko-resources auto-load bundle with identifier $loadedIdentifier at path $fullPath")
}

if (foundedBundle?.bundleIdentifier == identifier) return foundedBundle
Expand Down
7 changes: 7 additions & 0 deletions resources/src/appleMain/objective-c/MRResourcesBundle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#import <stdarg.h>
#import <Foundation/NSBundle.h>

@interface ResourcesBundleAnchor : NSObject
@end

NSBundle* getResourcesBundle();
14 changes: 14 additions & 0 deletions resources/src/appleMain/objective-c/MRResourcesBundle.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// clang -target arm64-apple-ios -isysroot $(xcrun --sdk iphoneos --show-sdk-path) -c MRResourcesBundle.m -o source.o
// ar rcs libMRResourcesBundle.a source.o
// lipo -info libMRResourcesBundle.a

#import <stdarg.h>
#import <Foundation/NSBundle.h>
#import "MRResourcesBundle.h"

@implementation ResourcesBundleAnchor
@end

NSBundle* getResourcesBundle() {
return [NSBundle bundleForClass:[ResourcesBundleAnchor class]];
}

0 comments on commit 49f7518

Please sign in to comment.