Skip to content

Commit 226759e

Browse files
authored
Merge pull request #67 from SDWebImage/project_add_available_for_lower_firmware_version
Support backward deployment on iOS 12 with CocoaPods and Carthage
2 parents 1582e80 + f2cb9d0 commit 226759e

File tree

13 files changed

+132
-11
lines changed

13 files changed

+132
-11
lines changed

Package.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ let package = Package(
2525
.target(
2626
name: "SDWebImageSwiftUI",
2727
dependencies: ["SDWebImage"],
28-
path: "SDWebImageSwiftUI/Classes",
29-
exclude: ["ObjC"]
28+
path: "SDWebImageSwiftUI/Classes"
3029
),
3130
]
3231
)

README.md

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ For more information, it's really recommended to check our demo, to learn detail
213213

214214
### Common Problems
215215

216-
+ Using Image/WebImage/AnimatedImage in Button/NavigationLink
216+
#### Using Image/WebImage/AnimatedImage in Button/NavigationLink
217217

218218
SwiftUI's `Button` apply overlay to its content (except `Text`) by default, this is common mistake to write code like this, which cause strange behavior:
219219

@@ -251,6 +251,65 @@ NavigationView {
251251
}
252252
```
253253

254+
#### Use for backward deployment and weak linking SwiftUI
255+
256+
SDWebImageSwiftUI supports to use when your App Target has a deployment target version less than iOS 13/macOS 10.15/tvOS 13/watchOS 6. Which will weak linking of SwiftUI(Combine) to allows writing code with available check at runtime.
257+
258+
To use backward deployment, you have to do the follow things:
259+
260+
+ Add `-weak_framework SwiftUI -weak_framework Combine` in your App Target's `Other Linker Flags` build setting
261+
262+
You should notice that all the third party SwiftUI framework should have this build setting as well, not only just ourself (we already added). Or when running on iOS 12 device, it will trigger the runtime dyld error on startup.
263+
264+
+ Use CocoaPods or Carthage (SwiftPM does not support weak linking nor backward deployment currently)
265+
266+
For Carthage user, the built binary framework will use [Library Evolution](https://swift.org/blog/abi-stability-and-more/) to support for backward deployment.
267+
268+
For CocoaPods user, you should skip the platform validation in Podfile with
269+
270+
```ruby
271+
platform :ios, '13.0' # This does not effect your App Target's deployment target version, just a hint for CocoaPods
272+
```
273+
274+
+ Add **all the SwiftUI code** with the available annotation and runtime check, like this:
275+
276+
```swift
277+
// AppDelegate.swift
278+
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
279+
// ...
280+
if #available(iOS 13, *) {
281+
window.rootViewController = UIHostingController(rootView: contentView)
282+
} else {
283+
window.rootViewController = ViewController()
284+
}
285+
// ...
286+
}
287+
288+
// ViewController.swift
289+
class ViewController: UIViewController {
290+
var label: UILabel = UILabel()
291+
override func viewDidLoad() {
292+
super.viewDidLoad()
293+
self.view.backgroundColor = .white
294+
self.view.addSubview(label)
295+
self.label.text = "Hello World iOS 12!"
296+
self.label.sizeToFit()
297+
self.label.center = self.view.center
298+
}
299+
}
300+
301+
// ContentView.swift
302+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
303+
struct ContentView : View {
304+
var body: some View {
305+
Group {
306+
Text("Hello World iOS 13!")
307+
WebImage(url: URL(string: "https://i.loli.net/2019/09/24/rX2RkVWeGKIuJvc.jpg"))
308+
}
309+
}
310+
}
311+
```
312+
254313
## Demo
255314

256315
To run the example using SwiftUI, following the steps:

SDWebImageSwiftUI.podspec

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,13 @@ It brings all your favorite features from SDWebImage, like async image loading,
2727
s.watchos.deployment_target = '6.0'
2828

2929
s.source_files = 'SDWebImageSwiftUI/Classes/**/*', 'SDWebImageSwiftUI/Module/*.h'
30+
s.pod_target_xcconfig = {
31+
'SUPPORTS_MACCATALYST' => 'YES',
32+
'DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER' => 'NO',
33+
'BUILD_LIBRARY_FOR_DISTRIBUTION' => 'YES'
34+
}
3035

31-
s.frameworks = 'SwiftUI'
36+
s.weak_frameworks = 'SwiftUI', 'Combine'
3237
s.dependency 'SDWebImage', '~> 5.3'
3338
s.swift_version = '5.1'
3439
end

SDWebImageSwiftUI.xcodeproj/project.pbxproj

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@
500500
isa = XCBuildConfiguration;
501501
buildSettings = {
502502
ALWAYS_SEARCH_USER_PATHS = NO;
503+
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
503504
CLANG_ANALYZER_NONNULL = YES;
504505
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
505506
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@@ -552,6 +553,12 @@
552553
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
553554
MTL_FAST_MATH = YES;
554555
ONLY_ACTIVE_ARCH = YES;
556+
OTHER_LDFLAGS = (
557+
"-weak_framework",
558+
SwiftUI,
559+
"-weak_framework",
560+
Combine,
561+
);
555562
SDKROOT = iphoneos;
556563
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
557564
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -566,6 +573,7 @@
566573
isa = XCBuildConfiguration;
567574
buildSettings = {
568575
ALWAYS_SEARCH_USER_PATHS = NO;
576+
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
569577
CLANG_ANALYZER_NONNULL = YES;
570578
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
571579
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@@ -611,6 +619,12 @@
611619
MACOSX_DEPLOYMENT_TARGET = 10.15;
612620
MTL_ENABLE_DEBUG_INFO = NO;
613621
MTL_FAST_MATH = YES;
622+
OTHER_LDFLAGS = (
623+
"-weak_framework",
624+
SwiftUI,
625+
"-weak_framework",
626+
Combine,
627+
);
614628
SDKROOT = iphoneos;
615629
SWIFT_COMPILATION_MODE = wholemodule;
616630
SWIFT_OPTIMIZATION_LEVEL = "-O";

SDWebImageSwiftUI/Classes/AnimatedImage.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import SDWebImage
1212
#if os(iOS) || os(tvOS) || os(macOS)
1313

1414
/// A coordinator object used for `AnimatedImage`native view bridge for UIKit/AppKit/WatchKit.
15+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
1516
public final class AnimatedImageCoordinator: NSObject {
1617

1718
/// Any user-provided object for actual coordinator, such as delegate method, taget-action
@@ -22,6 +23,7 @@ public final class AnimatedImageCoordinator: NSObject {
2223
}
2324

2425
/// Data Binding Object, only properties in this object can support changes from user with @State and refresh
26+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
2527
final class AnimatedImageModel : ObservableObject {
2628
/// URL image
2729
@Published var url: URL?
@@ -36,6 +38,7 @@ final class AnimatedImageModel : ObservableObject {
3638
}
3739

3840
/// Completion Handler Binding Object, supports dynamic @State changes
41+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
3942
final class AnimatedImageHandler: ObservableObject {
4043
// Completion Handler
4144
@Published var successBlock: ((PlatformImage, SDImageCacheType) -> Void)?
@@ -47,6 +50,7 @@ final class AnimatedImageHandler: ObservableObject {
4750
}
4851

4952
/// Layout Binding Object, supports dynamic @State changes
53+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
5054
final class AnimatedImageLayout : ObservableObject {
5155
var contentMode: ContentMode?
5256
var aspectRatio: CGFloat?
@@ -58,6 +62,7 @@ final class AnimatedImageLayout : ObservableObject {
5862
}
5963

6064
/// Configuration Binding Object, supports dynamic @State changes
65+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
6166
final class AnimatedImageConfiguration: ObservableObject {
6267
var incrementalLoad: Bool?
6368
var maxBufferSize: UInt?
@@ -73,6 +78,7 @@ final class AnimatedImageConfiguration: ObservableObject {
7378
}
7479

7580
/// A Image View type to load image from url, data or bundle. Supports animated and static image format.
81+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
7682
public struct AnimatedImage : PlatformViewRepresentable {
7783
@ObservedObject var imageModel = AnimatedImageModel()
7884
@ObservedObject var imageHandler = AnimatedImageHandler()
@@ -444,6 +450,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
444450
}
445451

446452
// Layout
453+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
447454
extension AnimatedImage {
448455

449456
/// Configurate this view's image with the specified cap insets and options.
@@ -483,6 +490,7 @@ extension AnimatedImage {
483490
}
484491

485492
// Aspect Ratio
493+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
486494
extension AnimatedImage {
487495
/// Constrains this view's dimensions to the specified aspect ratio.
488496
/// - Parameters:
@@ -541,6 +549,7 @@ extension AnimatedImage {
541549
}
542550

543551
// AnimatedImage Modifier
552+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
544553
extension AnimatedImage {
545554

546555
/// Total loop count for animated image rendering. Defaults to nil.
@@ -610,6 +619,7 @@ extension AnimatedImage {
610619
}
611620

612621
// Completion Handler
622+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
613623
extension AnimatedImage {
614624

615625
/// Provide the action when image load fails.
@@ -641,6 +651,7 @@ extension AnimatedImage {
641651
}
642652

643653
// View Coordinator Handler
654+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
644655
extension AnimatedImage {
645656

646657
/// Provide the action when view representable create the native view.
@@ -668,6 +679,7 @@ extension AnimatedImage {
668679
}
669680

670681
// Web Image convenience
682+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
671683
extension AnimatedImage {
672684

673685
/// Associate a placeholder when loading image with url
@@ -695,6 +707,7 @@ extension AnimatedImage {
695707
}
696708

697709
#if DEBUG
710+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
698711
struct AnimatedImage_Previews : PreviewProvider {
699712
static var previews: some View {
700713
Group {

SDWebImageSwiftUI/Classes/ImageManager.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import SwiftUI
1010
import SDWebImage
1111

12+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
1213
class ImageManager : ObservableObject {
1314
@Published var image: PlatformImage? // loaded image, note when progressive loading, this will published multiple times with different partial image
1415
@Published var isLoading: Bool = false // whether network is loading or cache is querying, should only be used for indicator binding

SDWebImageSwiftUI/Classes/ImageViewWrapper.swift

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import SDWebImage
1212
#if os(iOS) || os(tvOS) || os(macOS)
1313

1414
/// Use wrapper to solve tne `UIImageView`/`NSImageView` frame size become image size issue (SwiftUI's Bug)
15+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
1516
public class AnimatedImageViewWrapper : PlatformView {
1617
var wrapped = SDAnimatedImageView()
1718
var interpolationQuality = CGInterpolationQuality.default
@@ -67,29 +68,33 @@ public class AnimatedImageViewWrapper : PlatformView {
6768
}
6869
}
6970

70-
private var sd_imageNameKey: Void?
71-
private var sd_imageDataKey: Void?
71+
7272
/// Store the Animated Image loading state, to avoid re-query duinrg `updateView(_:)` until Source of Truth changes
73+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
7374
extension PlatformView {
75+
static private var sd_imageNameKey: Void?
76+
static private var sd_imageDataKey: Void?
77+
7478
var sd_imageName: String? {
7579
get {
76-
objc_getAssociatedObject(self, &sd_imageNameKey) as? String
80+
objc_getAssociatedObject(self, &PlatformView.sd_imageNameKey) as? String
7781
}
7882
set {
79-
objc_setAssociatedObject(self, &sd_imageNameKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
83+
objc_setAssociatedObject(self, &PlatformView.sd_imageNameKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
8084
}
8185
}
8286
var sd_imageData: Data? {
8387
get {
84-
objc_getAssociatedObject(self, &sd_imageDataKey) as? Data
88+
objc_getAssociatedObject(self, &PlatformView.sd_imageDataKey) as? Data
8589
}
8690
set {
87-
objc_setAssociatedObject(self, &sd_imageDataKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
91+
objc_setAssociatedObject(self, &PlatformView.sd_imageDataKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
8892
}
8993
}
9094
}
9195

9296
/// Use wrapper to solve the `UIProgressView`/`NSProgressIndicator` frame origin NaN crash (SwiftUI's bug)
97+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
9398
public class ProgressIndicatorWrapper : PlatformView {
9499
#if os(macOS)
95100
var wrapped = NSProgressIndicator()

SDWebImageSwiftUI/Classes/Indicator/ActivityIndicator.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import SwiftUI
1010

1111
#if os(macOS) || os(iOS) || os(tvOS)
1212
/// An activity indicator (system style)
13+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
1314
public struct ActivityIndicator: PlatformViewRepresentable {
1415
@Binding var isAnimating: Bool
1516
var style: Style
@@ -71,6 +72,7 @@ public struct ActivityIndicator: PlatformViewRepresentable {
7172
#endif
7273
}
7374

75+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
7476
extension ActivityIndicator {
7577
public enum Style {
7678
case medium

SDWebImageSwiftUI/Classes/Indicator/Indicator.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Foundation
1010
import SwiftUI
1111

1212
/// A type to build the indicator
13+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
1314
public struct Indicator<T> where T : View {
1415
var content: (Binding<Bool>, Binding<CGFloat>) -> T
1516

@@ -26,6 +27,7 @@ public struct Indicator<T> where T : View {
2627
/// A implementation detail View Modifier with indicator
2728
/// SwiftUI View Modifier construced by using a internal View type which modify the `body`
2829
/// It use type system to represent the view hierarchy, and Swift `some View` syntax to hide the type detail for users
30+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
2931
struct IndicatorViewModifier<T> : ViewModifier where T : View {
3032
@ObservedObject var imageManager: ImageManager
3133

@@ -44,6 +46,7 @@ struct IndicatorViewModifier<T> : ViewModifier where T : View {
4446
}
4547

4648
#if os(macOS) || os(iOS) || os(tvOS)
49+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
4750
extension Indicator where T == ActivityIndicator {
4851
/// Activity Indicator
4952
public static var activity: Indicator {
@@ -61,6 +64,7 @@ extension Indicator where T == ActivityIndicator {
6164
}
6265
}
6366

67+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
6468
extension Indicator where T == ProgressIndicator {
6569
/// Progress Indicator
6670
public static var progress: Indicator {

SDWebImageSwiftUI/Classes/Indicator/ProgressIndicator.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import SwiftUI
1010

1111
#if os(macOS) || os(iOS) || os(tvOS)
1212
/// A progress bar indicator (system style)
13+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
1314
public struct ProgressIndicator: PlatformViewRepresentable {
1415
@Binding var isAnimating: Bool
1516
@Binding var progress: CGFloat
@@ -101,6 +102,7 @@ public struct ProgressIndicator: PlatformViewRepresentable {
101102
#endif
102103
}
103104

105+
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
104106
extension ProgressIndicator {
105107
public enum Style {
106108
case `default`

0 commit comments

Comments
 (0)