diff --git a/Package.swift b/Package.swift index 87b80cf242..05f1b9f4db 100644 --- a/Package.swift +++ b/Package.swift @@ -26,7 +26,7 @@ extension Target { extension Target { static func rxCocoa() -> [Target] { - #if os(Linux) + #if os(Linux) || os(Android) return [.rxTarget(name: "RxCocoa", dependencies: ["RxSwift", "RxRelay"])] #else return [.rxTarget(name: "RxCocoa", dependencies: ["RxSwift", "RxRelay", "RxCocoaRuntime"])] @@ -34,7 +34,7 @@ extension Target { } static func rxCocoaRuntime() -> [Target] { - #if os(Linux) + #if os(Linux) || os(Android) return [] #else return [.rxTarget(name: "RxCocoaRuntime", dependencies: ["RxSwift"])] diff --git a/Package@swift-5.9.swift b/Package@swift-5.9.swift index da26d14aba..dab782d162 100644 --- a/Package@swift-5.9.swift +++ b/Package@swift-5.9.swift @@ -26,7 +26,7 @@ extension Target { extension Target { static func rxCocoa() -> [Target] { - #if os(Linux) + #if os(Linux) || os(Android) return [.rxTarget(name: "RxCocoa", dependencies: ["RxSwift", "RxRelay"])] #else return [.rxTarget(name: "RxCocoa", dependencies: ["RxSwift", "RxRelay", "RxCocoaRuntime"])] @@ -34,7 +34,7 @@ extension Target { } static func rxCocoaRuntime() -> [Target] { - #if os(Linux) + #if os(Linux) || os(Android) return [] #else return [.rxTarget(name: "RxCocoaRuntime", dependencies: ["RxSwift"])] diff --git a/Platform/Platform.Android.swift b/Platform/Platform.Android.swift new file mode 100644 index 0000000000..bd81d7518c --- /dev/null +++ b/Platform/Platform.Android.swift @@ -0,0 +1,32 @@ +// +// Platform.Android.swift +// Platform +// +// Created by Jake Prickett on 8/24/25. +// Copyright © 2025 Krunoslav Zaher. All rights reserved. +// + +#if os(Android) + + import Foundation + + extension Thread { + + static func setThreadLocalStorageValue(_ value: T?, forKey key: String) { + if let newValue = value { + Thread.current.threadDictionary[key] = newValue + } + else { + Thread.current.threadDictionary[key] = nil + } + } + + static func getThreadLocalStorageValueForKey(_ key: String) -> T? { + let currentThread = Thread.current + let threadDictionary = currentThread.threadDictionary + + return threadDictionary[key] as? T + } + } + +#endif \ No newline at end of file diff --git a/RxBlocking/Platform/Platform.Android.swift b/RxBlocking/Platform/Platform.Android.swift new file mode 120000 index 0000000000..549313bd79 --- /dev/null +++ b/RxBlocking/Platform/Platform.Android.swift @@ -0,0 +1 @@ +../../Platform/Platform.Android.swift \ No newline at end of file diff --git a/RxBlocking/RunLoopLock.swift b/RxBlocking/RunLoopLock.swift index cc8c9e00dc..ebb53ff32d 100644 --- a/RxBlocking/RunLoopLock.swift +++ b/RxBlocking/RunLoopLock.swift @@ -10,7 +10,7 @@ import CoreFoundation import Foundation import RxSwift -#if os(Linux) +#if os(Linux) || os(Android) import Foundation let runLoopMode: RunLoop.Mode = .default let runLoopModeRaw: CFString = unsafeBitCast(runLoopMode.rawValue._bridgeToObjectiveC(), to: CFString.self) @@ -61,7 +61,7 @@ final class RunLoopLock { fatalError("Run can be only called once") } if let timeout = self.timeout { - #if os(Linux) + #if os(Linux) || os(Android) let runLoopResult = CFRunLoopRunInMode(runLoopModeRaw, timeout, false) #else let runLoopResult = CFRunLoopRunInMode(runLoopMode, timeout, false) diff --git a/RxCocoa/Common/DelegateProxy.swift b/RxCocoa/Common/DelegateProxy.swift index d103448e73..fa78b6fe53 100644 --- a/RxCocoa/Common/DelegateProxy.swift +++ b/RxCocoa/Common/DelegateProxy.swift @@ -6,10 +6,10 @@ // Copyright © 2015 Krunoslav Zaher. All rights reserved. // -#if !os(Linux) +#if !os(Linux) && !os(Android) import RxSwift - #if SWIFT_PACKAGE && !os(Linux) + #if SWIFT_PACKAGE && !os(Linux) && !os(Android) import RxCocoaRuntime #endif diff --git a/RxCocoa/Common/DelegateProxyType.swift b/RxCocoa/Common/DelegateProxyType.swift index 0e7448a54d..006e5ad7f4 100644 --- a/RxCocoa/Common/DelegateProxyType.swift +++ b/RxCocoa/Common/DelegateProxyType.swift @@ -6,7 +6,7 @@ // Copyright © 2015 Krunoslav Zaher. All rights reserved. // -#if !os(Linux) +#if !os(Linux) && !os(Android) import Foundation import RxSwift diff --git a/RxCocoa/Common/RxCocoaObjCRuntimeError+Extensions.swift b/RxCocoa/Common/RxCocoaObjCRuntimeError+Extensions.swift index 4abf8808cd..d21691e622 100644 --- a/RxCocoa/Common/RxCocoaObjCRuntimeError+Extensions.swift +++ b/RxCocoa/Common/RxCocoaObjCRuntimeError+Extensions.swift @@ -6,11 +6,11 @@ // Copyright © 2016 Krunoslav Zaher. All rights reserved. // -#if SWIFT_PACKAGE && !DISABLE_SWIZZLING && !os(Linux) +#if SWIFT_PACKAGE && !DISABLE_SWIZZLING && !os(Linux) && !os(Android) import RxCocoaRuntime #endif -#if !DISABLE_SWIZZLING && !os(Linux) +#if !DISABLE_SWIZZLING && !os(Linux) && !os(Android) /// RxCocoa ObjC runtime interception mechanism. public enum RxCocoaInterceptionMechanism { /// Unknown message interception mechanism. diff --git a/RxCocoa/Foundation/KVORepresentable+CoreGraphics.swift b/RxCocoa/Foundation/KVORepresentable+CoreGraphics.swift index 30026bf995..3aa2bfe55b 100644 --- a/RxCocoa/Foundation/KVORepresentable+CoreGraphics.swift +++ b/RxCocoa/Foundation/KVORepresentable+CoreGraphics.swift @@ -6,7 +6,7 @@ // Copyright © 2015 Krunoslav Zaher. All rights reserved. // -#if !os(Linux) +#if !os(Linux) && !os(Android) import RxSwift import CoreGraphics diff --git a/RxCocoa/Foundation/NSObject+Rx+KVORepresentable.swift b/RxCocoa/Foundation/NSObject+Rx+KVORepresentable.swift index 1be5a212dc..bc4e0f5064 100644 --- a/RxCocoa/Foundation/NSObject+Rx+KVORepresentable.swift +++ b/RxCocoa/Foundation/NSObject+Rx+KVORepresentable.swift @@ -6,7 +6,7 @@ // Copyright © 2015 Krunoslav Zaher. All rights reserved. // -#if !os(Linux) +#if !os(Linux) && !os(Android) import Foundation import RxSwift @@ -42,7 +42,7 @@ extension Reactive where Base: NSObject { } } -#if !DISABLE_SWIZZLING && !os(Linux) +#if !DISABLE_SWIZZLING && !os(Linux) && !os(Android) // KVO extension Reactive where Base: NSObject { /** diff --git a/RxCocoa/Foundation/NSObject+Rx+RawRepresentable.swift b/RxCocoa/Foundation/NSObject+Rx+RawRepresentable.swift index 6e47cb2432..32fb7807fd 100644 --- a/RxCocoa/Foundation/NSObject+Rx+RawRepresentable.swift +++ b/RxCocoa/Foundation/NSObject+Rx+RawRepresentable.swift @@ -6,7 +6,7 @@ // Copyright © 2015 Krunoslav Zaher. All rights reserved. // -#if !os(Linux) +#if !os(Linux) && !os(Android) import RxSwift diff --git a/RxCocoa/Foundation/NSObject+Rx.swift b/RxCocoa/Foundation/NSObject+Rx.swift index 2f15724162..cea4b1e11d 100644 --- a/RxCocoa/Foundation/NSObject+Rx.swift +++ b/RxCocoa/Foundation/NSObject+Rx.swift @@ -6,7 +6,7 @@ // Copyright © 2015 Krunoslav Zaher. All rights reserved. // -#if !os(Linux) +#if !os(Linux) && !os(Android) import Foundation import RxSwift @@ -14,14 +14,14 @@ import RxSwift import RxCocoaRuntime #endif -#if !DISABLE_SWIZZLING && !os(Linux) +#if !DISABLE_SWIZZLING && !os(Linux) && !os(Android) private var deallocatingSubjectTriggerContext: UInt8 = 0 private var deallocatingSubjectContext: UInt8 = 0 #endif private var deallocatedSubjectTriggerContext: UInt8 = 0 private var deallocatedSubjectContext: UInt8 = 0 -#if !os(Linux) +#if !os(Linux) && !os(Android) /** KVO is a tricky mechanism. @@ -95,7 +95,7 @@ extension Reactive where Base: NSObject { #endif -#if !DISABLE_SWIZZLING && !os(Linux) +#if !DISABLE_SWIZZLING && !os(Linux) && !os(Android) // KVO extension Reactive where Base: NSObject { /** @@ -144,7 +144,7 @@ extension Reactive where Base: AnyObject { } } -#if !DISABLE_SWIZZLING && !os(Linux) +#if !DISABLE_SWIZZLING && !os(Linux) && !os(Android) /** Observable sequence of message arguments that completes when object is deallocated. @@ -264,7 +264,7 @@ extension Reactive where Base: AnyObject { // MARK: Message interceptors -#if !DISABLE_SWIZZLING && !os(Linux) +#if !DISABLE_SWIZZLING && !os(Linux) && !os(Android) private protocol MessageInterceptorSubject: AnyObject { init() @@ -349,7 +349,7 @@ private final class DeallocObservable { // MARK: KVO -#if !os(Linux) +#if !os(Linux) && !os(Android) private protocol KVOObservableProtocol { var target: AnyObject { get } @@ -438,7 +438,7 @@ private extension KeyValueObservingOptions { #endif -#if !DISABLE_SWIZZLING && !os(Linux) +#if !DISABLE_SWIZZLING && !os(Linux) && !os(Android) private func observeWeaklyKeyPathFor(_ target: NSObject, keyPath: String, options: KeyValueObservingOptions) -> Observable { let components = keyPath.components(separatedBy: ".").filter { $0 != "self" } diff --git a/RxCocoa/Traits/SharedSequence/SharedSequence+Concurrency.swift b/RxCocoa/Traits/SharedSequence/SharedSequence+Concurrency.swift index 027c2b0be9..b2015372a1 100644 --- a/RxCocoa/Traits/SharedSequence/SharedSequence+Concurrency.swift +++ b/RxCocoa/Traits/SharedSequence/SharedSequence+Concurrency.swift @@ -6,7 +6,7 @@ // Copyright © 2021 Krunoslav Zaher. All rights reserved. // -#if swift(>=5.6) && canImport(_Concurrency) && !os(Linux) +#if swift(>=5.6) && canImport(_Concurrency) && !os(Linux) && !os(Android) import Foundation // MARK: - Shared Sequence diff --git a/RxSwift/Platform/Platform.Android.swift b/RxSwift/Platform/Platform.Android.swift new file mode 120000 index 0000000000..549313bd79 --- /dev/null +++ b/RxSwift/Platform/Platform.Android.swift @@ -0,0 +1 @@ +../../Platform/Platform.Android.swift \ No newline at end of file diff --git a/RxSwift/RxMutableBox.swift b/RxSwift/RxMutableBox.swift index 73476c367e..b473ef478a 100644 --- a/RxSwift/RxMutableBox.swift +++ b/RxSwift/RxMutableBox.swift @@ -6,7 +6,7 @@ // Copyright © 2015 Krunoslav Zaher. All rights reserved. // -#if os(Linux) +#if os(Linux) || os(Android) /// As Swift 5 was released, A patch to `Thread` for Linux /// changed `threadDictionary` to a `NSMutableDictionary` instead of /// a `Dictionary`: https://github.com/apple/swift-corelibs-foundation/pull/1762/files diff --git a/RxSwift/Schedulers/CurrentThreadScheduler.swift b/RxSwift/Schedulers/CurrentThreadScheduler.swift index 16a7dd328e..eab5c6b2c9 100644 --- a/RxSwift/Schedulers/CurrentThreadScheduler.swift +++ b/RxSwift/Schedulers/CurrentThreadScheduler.swift @@ -9,7 +9,7 @@ import Dispatch import Foundation -#if os(Linux) +#if os(Linux) || os(Android) fileprivate enum CurrentThreadSchedulerQueueKey { fileprivate static let instance = "RxSwift.CurrentThreadScheduler.Queue" } diff --git a/Sources/AllTestz/Platform.Android.swift b/Sources/AllTestz/Platform.Android.swift new file mode 120000 index 0000000000..549313bd79 --- /dev/null +++ b/Sources/AllTestz/Platform.Android.swift @@ -0,0 +1 @@ +../../Platform/Platform.Android.swift \ No newline at end of file diff --git a/Sources/RxBlocking/Platform.Android.swift b/Sources/RxBlocking/Platform.Android.swift new file mode 120000 index 0000000000..549313bd79 --- /dev/null +++ b/Sources/RxBlocking/Platform.Android.swift @@ -0,0 +1 @@ +../../Platform/Platform.Android.swift \ No newline at end of file diff --git a/Sources/RxSwift/Platform.Android.swift b/Sources/RxSwift/Platform.Android.swift new file mode 120000 index 0000000000..549313bd79 --- /dev/null +++ b/Sources/RxSwift/Platform.Android.swift @@ -0,0 +1 @@ +../../Platform/Platform.Android.swift \ No newline at end of file diff --git a/Tests/Platform/Platform.Android.swift b/Tests/Platform/Platform.Android.swift new file mode 120000 index 0000000000..549313bd79 --- /dev/null +++ b/Tests/Platform/Platform.Android.swift @@ -0,0 +1 @@ +../../Platform/Platform.Android.swift \ No newline at end of file diff --git a/scripts/validate-headers.swift b/scripts/validate-headers.swift index 48b36eb407..73e7f23933 100755 --- a/scripts/validate-headers.swift +++ b/scripts/validate-headers.swift @@ -45,6 +45,7 @@ let excludePaths = [ "AllTestz/main.swift", "Platform/AtomicInt.swift", "Platform/Platform.Linux.swift", + "Platform/Platform.Android.swift", "Platform/Platform.Darwin.swift", "Platform/RecursiveLock.swift", "Platform/DataStructures/Bag.swift",