mirror of
https://github.com/easychen/pushdeer.git
synced 2025-02-22 16:04:56 +08:00
commit
d58f6da266
@ -1,6 +1,8 @@
|
||||
# Uncomment the next line to define a global platform for your project
|
||||
platform :ios, '14.0'
|
||||
|
||||
load 'remove_unsupported_libraries.rb'
|
||||
|
||||
# Comment the next line if you don't want to use dynamic frameworks
|
||||
use_frameworks!
|
||||
|
||||
@ -10,14 +12,14 @@ def commonPods
|
||||
pod 'SDWebImageSwiftUI', '~> 2.0.2'
|
||||
pod 'KRProgressHUD', '~> 3.4.7'
|
||||
pod 'IQKeyboardManagerSwift', '~> 6.5.9'
|
||||
|
||||
# pod 'WoodPeckeriOS', :configurations => ['Debug']
|
||||
end
|
||||
|
||||
target 'PushDeer' do
|
||||
commonPods
|
||||
# Pods for PushDeer
|
||||
|
||||
# PushDeer 独享的依赖, Clip 不支持
|
||||
pod 'WechatOpenSDK', '~> 1.8.7.1'
|
||||
pod 'WoodPeckeriOS', :configurations => ['Debug']
|
||||
end
|
||||
|
||||
target 'PushDeerClip' do
|
||||
@ -25,3 +27,20 @@ target 'PushDeerClip' do
|
||||
# Pods for PushDeerClip
|
||||
|
||||
end
|
||||
|
||||
# define unsupported pods
|
||||
def unsupported_pods
|
||||
# macCatalyst 不支持的库
|
||||
['WoodPeckeriOS', 'WechatOpenSDK']
|
||||
end
|
||||
|
||||
def supported_pods
|
||||
# macCatalyst 支持的库
|
||||
['Moya', 'SDWebImageSwiftUI', 'KRProgressHUD', 'IQKeyboardManagerSwift']
|
||||
end
|
||||
|
||||
# install all pods except unsupported ones
|
||||
post_install do |installer|
|
||||
$verbose = false # remove or set to false to avoid printing
|
||||
installer.configure_support_catalyst(supported_pods, unsupported_pods)
|
||||
end
|
||||
|
@ -13,12 +13,16 @@ PODS:
|
||||
- SDWebImage/Core (5.12.1)
|
||||
- SDWebImageSwiftUI (2.0.2):
|
||||
- SDWebImage (~> 5.10)
|
||||
- WechatOpenSDK (1.8.7.1)
|
||||
- WoodPeckeriOS (1.2.93)
|
||||
|
||||
DEPENDENCIES:
|
||||
- IQKeyboardManagerSwift (~> 6.5.9)
|
||||
- KRProgressHUD (~> 3.4.7)
|
||||
- Moya (~> 15.0)
|
||||
- SDWebImageSwiftUI (~> 2.0.2)
|
||||
- WechatOpenSDK (~> 1.8.7.1)
|
||||
- WoodPeckeriOS
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
@ -29,6 +33,8 @@ SPEC REPOS:
|
||||
- Moya
|
||||
- SDWebImage
|
||||
- SDWebImageSwiftUI
|
||||
- WechatOpenSDK
|
||||
- WoodPeckeriOS
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: 1c4fb5369c3fe93d2857c780d8bbe09f06f97e7c
|
||||
@ -38,7 +44,9 @@ SPEC CHECKSUMS:
|
||||
Moya: 138f0573e53411fb3dc17016add0b748dfbd78ee
|
||||
SDWebImage: 4dc3e42d9ec0c1028b960a33ac6b637bb432207b
|
||||
SDWebImageSwiftUI: 8a3923c95108312b03a599ec1498754af55a6819
|
||||
WechatOpenSDK: 6a4d1436c15b3b5fe2a0bd383f3046010186da44
|
||||
WoodPeckeriOS: 12ec7f38c695e51cd94a476228888dfe85d9d916
|
||||
|
||||
PODFILE CHECKSUM: 3c8d668f811e3c29bb70fc8a24d2ecd9c266ba45
|
||||
PODFILE CHECKSUM: 1b349626994062a8291e3db07d3dbf087894c4d2
|
||||
|
||||
COCOAPODS: 1.11.2
|
||||
|
@ -77,9 +77,13 @@
|
||||
52EB90AE2778AFD60048E0ED /* BaseNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EB90AD2778AFD60048E0ED /* BaseNavigationView.swift */; };
|
||||
52EB90B02778D67F0048E0ED /* KeyItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EB90AF2778D67F0048E0ED /* KeyItemView.swift */; };
|
||||
52EB90B32778DA4E0048E0ED /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EB90B22778DA4E0048E0ED /* Line.swift */; };
|
||||
52EED71E27C9394D0086A804 /* WXDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EED71D27C9394D0086A804 /* WXDelegate.swift */; };
|
||||
52EED71F27C93B960086A804 /* WXDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EED71D27C9394D0086A804 /* WXDelegate.swift */; };
|
||||
52F0243F277737470071D861 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F0243E277737470071D861 /* LoginView.swift */; };
|
||||
52F2C223277961D7006F08DC /* SettingsItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F2C222277961D7006F08DC /* SettingsItemView.swift */; };
|
||||
52F40D2F277CA05600766C24 /* MessageItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F40D2E277CA05600766C24 /* MessageItemView.swift */; };
|
||||
52FB1FEC27CA9D7300367DE0 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52FB1FEB27CA9D7300367DE0 /* SafariView.swift */; };
|
||||
52FB1FED27CA9D7300367DE0 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52FB1FEB27CA9D7300367DE0 /* SafariView.swift */; };
|
||||
52FBA09427874879003308C2 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5292F4FA2776BC7900B9A7BB /* ContentView.swift */; };
|
||||
64B0C15E70CCC382B480F76E /* Pods_PushDeer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E380A18349DE4D26071E913E /* Pods_PushDeer.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
@ -143,6 +147,7 @@
|
||||
52B8CF6D277E0B46004CB680 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||
52B8CF6F277E0B46004CB680 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
52B8CF70277E0B46004CB680 /* PushDeerClip.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = PushDeerClip.entitlements; sourceTree = "<group>"; };
|
||||
52BE373227C236DD004AA630 /* PushDeer-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PushDeer-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
52E317D8279305BB000B8BB1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
52E317DB279305BB000B8BB1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
52E317DE279305BB000B8BB1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
@ -153,10 +158,12 @@
|
||||
52EB90AD2778AFD60048E0ED /* BaseNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseNavigationView.swift; sourceTree = "<group>"; };
|
||||
52EB90AF2778D67F0048E0ED /* KeyItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyItemView.swift; sourceTree = "<group>"; };
|
||||
52EB90B22778DA4E0048E0ED /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
|
||||
52EED71D27C9394D0086A804 /* WXDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WXDelegate.swift; sourceTree = "<group>"; };
|
||||
52F0243C277733CE0071D861 /* PushDeer.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = PushDeer.entitlements; sourceTree = "<group>"; };
|
||||
52F0243E277737470071D861 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
|
||||
52F2C222277961D7006F08DC /* SettingsItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsItemView.swift; sourceTree = "<group>"; };
|
||||
52F40D2E277CA05600766C24 /* MessageItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageItemView.swift; sourceTree = "<group>"; };
|
||||
52FB1FEB27CA9D7300367DE0 /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = "<group>"; };
|
||||
69F56B2711ED98819D474BE3 /* Pods-PushDeerClip.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PushDeerClip.debug.xcconfig"; path = "Target Support Files/Pods-PushDeerClip/Pods-PushDeerClip.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
8B9D658D778AE868A0E052A8 /* Pods-PushDeer.debug-selfhosted.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PushDeer.debug-selfhosted.xcconfig"; path = "Target Support Files/Pods-PushDeer/Pods-PushDeer.debug-selfhosted.xcconfig"; sourceTree = "<group>"; };
|
||||
9CC775BE0326BF31C6FACF06 /* Pods-PushDeerClip.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PushDeerClip.release.xcconfig"; path = "Target Support Files/Pods-PushDeerClip/Pods-PushDeerClip.release.xcconfig"; sourceTree = "<group>"; };
|
||||
@ -213,6 +220,7 @@
|
||||
52450F3A278491F8003652D8 /* AppState.swift */,
|
||||
52450F412784943F003652D8 /* HttpRequest.swift */,
|
||||
526A1E722791E03900BA2177 /* Persistence.swift */,
|
||||
52EED71D27C9394D0086A804 /* WXDelegate.swift */,
|
||||
);
|
||||
path = Service;
|
||||
sourceTree = "<group>";
|
||||
@ -264,6 +272,7 @@
|
||||
52483FC1277ED6D5003A100E /* AppDelegate.swift */,
|
||||
5292F4F82776BC7900B9A7BB /* PushDeerApp.swift */,
|
||||
5292F4FA2776BC7900B9A7BB /* ContentView.swift */,
|
||||
52BE373227C236DD004AA630 /* PushDeer-Bridging-Header.h */,
|
||||
5292F4FC2776BC7A00B9A7BB /* Assets.xcassets */,
|
||||
5292F4FE2776BC7A00B9A7BB /* Preview Content */,
|
||||
);
|
||||
@ -285,6 +294,7 @@
|
||||
52B8CF5E277DE660004CB680 /* AppleSignInButton.swift */,
|
||||
52AC5C2727B7FE1D00EEB185 /* ViewExtension.swift */,
|
||||
52AC5C2A27B8206D00EEB185 /* ListTest.swift */,
|
||||
52FB1FEB27CA9D7300367DE0 /* SafariView.swift */,
|
||||
);
|
||||
path = Common;
|
||||
sourceTree = "<group>";
|
||||
@ -410,9 +420,11 @@
|
||||
TargetAttributes = {
|
||||
5292F4F42776BC7900B9A7BB = {
|
||||
CreatedOnToolsVersion = 13.2.1;
|
||||
LastSwiftMigration = 1320;
|
||||
};
|
||||
52B8CF63277E0B44004CB680 = {
|
||||
CreatedOnToolsVersion = 13.2.1;
|
||||
LastSwiftMigration = 1320;
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -551,6 +563,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
52F0243F277737470071D861 /* LoginView.swift in Sources */,
|
||||
52FB1FEC27CA9D7300367DE0 /* SafariView.swift in Sources */,
|
||||
523150DC2778762B00941EDC /* DeviceItemView.swift in Sources */,
|
||||
523150D9277875FB00941EDC /* DeletableView.swift in Sources */,
|
||||
52163EBB277741AC00594190 /* SettingsView.swift in Sources */,
|
||||
@ -571,6 +584,7 @@
|
||||
526A1E7D2792B2A600BA2177 /* MessageModel.swift in Sources */,
|
||||
52483FC2277ED6D5003A100E /* AppDelegate.swift in Sources */,
|
||||
52450F3827848243003652D8 /* PushDeerApi.swift in Sources */,
|
||||
52EED71E27C9394D0086A804 /* WXDelegate.swift in Sources */,
|
||||
52EB90AE2778AFD60048E0ED /* BaseNavigationView.swift in Sources */,
|
||||
524E99E627B3CD0F00292396 /* EndpointView.swift in Sources */,
|
||||
52EB90AC2778ADF80048E0ED /* CardView.swift in Sources */,
|
||||
@ -589,6 +603,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
52B8CF82277E0C06004CB680 /* AppleSignInButton.swift in Sources */,
|
||||
52FB1FED27CA9D7300367DE0 /* SafariView.swift in Sources */,
|
||||
52B8CF78277E0BF1004CB680 /* MainView.swift in Sources */,
|
||||
52B8CF79277E0BFB004CB680 /* DeviceListView.swift in Sources */,
|
||||
52B8CF84277E0C12004CB680 /* CardView.swift in Sources */,
|
||||
@ -609,6 +624,7 @@
|
||||
526A1E7E2792B2A600BA2177 /* MessageModel.swift in Sources */,
|
||||
52483FC3277ED6D5003A100E /* AppDelegate.swift in Sources */,
|
||||
52450F3927848243003652D8 /* PushDeerApi.swift in Sources */,
|
||||
52EED71F27C93B960086A804 /* WXDelegate.swift in Sources */,
|
||||
52B8CF86277E0C12004CB680 /* BaseNavigationView.swift in Sources */,
|
||||
524E99E727B3CD0F00292396 /* EndpointView.swift in Sources */,
|
||||
52FBA09427874879003308C2 /* ContentView.swift in Sources */,
|
||||
@ -733,6 +749,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-SH";
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "PushDeer/PushDeer-SelfHosted.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
@ -760,6 +777,8 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "PushDeer/PushDeer-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@ -771,6 +790,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-SH";
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "PushDeerClip/PushDeerClip-SelfHosted.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
@ -801,6 +821,8 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pushdeer.self.ios.Clip;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "PushDeer/PushDeer-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@ -870,6 +892,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-SH";
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "PushDeer/PushDeer-SelfHosted.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
@ -897,6 +920,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "PushDeer/PushDeer-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@ -908,6 +932,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-SH";
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "PushDeerClip/PushDeerClip-SelfHosted.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
@ -938,6 +963,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pushdeer.self.ios.Clip;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "PushDeer/PushDeer-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@ -1067,6 +1093,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = PushDeer/PushDeer.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
@ -1094,6 +1121,8 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "PushDeer/PushDeer-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@ -1105,6 +1134,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = PushDeer/PushDeer.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
@ -1132,6 +1162,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "PushDeer/PushDeer-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@ -1143,6 +1174,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = PushDeerClip/PushDeerClip.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
@ -1173,6 +1205,8 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pushdeer.app.ios.Clip;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "PushDeer/PushDeer-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@ -1184,6 +1218,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = PushDeerClip/PushDeerClip.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
@ -1214,6 +1249,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.pushdeer.app.ios.Clip;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "PushDeer/PushDeer-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@ -1262,8 +1298,8 @@
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/gonzalezreal/MarkdownUI";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 0.5.2;
|
||||
kind = upToNextMinorVersion;
|
||||
minimumVersion = 1.0.0;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
@ -2,6 +2,8 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
|
||||
<false/>
|
||||
<key>PreviewsEnabled</key>
|
||||
<false/>
|
||||
</dict>
|
||||
|
@ -6,8 +6,8 @@
|
||||
"repositoryURL": "https://github.com/gonzalezreal/AttributedText",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "c345033e22d5a1cd0e9fe0ec405cc809a8349586",
|
||||
"version": "0.3.1"
|
||||
"revision": "2dc2d7864e0fee4b524a5850d7d7cf9a7eeda0fc",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -24,8 +24,8 @@
|
||||
"repositoryURL": "https://github.com/gonzalezreal/MarkdownUI",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "29d94710545952dd4c724cc2ca901848eef54ded",
|
||||
"version": "0.5.2"
|
||||
"revision": "94e07c111f1ef0a9c997d2fadac984e8bb7d7405",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -33,17 +33,8 @@
|
||||
"repositoryURL": "https://github.com/gonzalezreal/NetworkImage",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "04167e81ed89a14b5da9b856ead306b969bb5abd",
|
||||
"version": "3.1.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "cmark",
|
||||
"repositoryURL": "https://github.com/SwiftDocOrg/swift-cmark.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "9c8096a23f44794bde297452d87c455fc4f76d42",
|
||||
"version": "0.29.0+20210102.9c8096a"
|
||||
"revision": "f8b8ed0be39d2f4aa00a6e8d3b18a62a94eff8d8",
|
||||
"version": "4.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -51,8 +42,8 @@
|
||||
"repositoryURL": "https://github.com/gonzalezreal/SwiftCommonMark",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "ed60da54305c244d0f77bc8d08495e04161e96a4",
|
||||
"version": "0.1.2"
|
||||
"revision": "ed252beaddecce28ea6363f800c773d6169011b8",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -9,6 +9,7 @@ import UIKit
|
||||
import UserNotifications
|
||||
import IQKeyboardManagerSwift
|
||||
|
||||
@MainActor
|
||||
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
|
||||
@ -35,6 +36,12 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
|
||||
IQKeyboardManager.shared.enable = false // 键盘与输入框的距离管理 禁用
|
||||
IQKeyboardManager.shared.enableAutoToolbar = true // 键盘上方添加的工具栏 启用
|
||||
|
||||
#if !targetEnvironment(macCatalyst) && !APPCLIP && !SELFHOSTED
|
||||
// 非Mac and 非AppClip and 非自架版
|
||||
// 向微信注册
|
||||
WXApi.registerApp(Env.wxAppid, universalLink: Env.wxUniversalLink)
|
||||
#endif
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "100",
|
||||
"green" : "191",
|
||||
"red" : "31"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "0.000",
|
||||
"blue" : "0",
|
||||
"green" : "0",
|
||||
"red" : "0"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "1.000",
|
||||
"green" : "1.000",
|
||||
"red" : "1.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "100",
|
||||
"green" : "191",
|
||||
"red" : "31"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
21
ios/PushDeer-iOS/PushDeer/Assets.xcassets/Images/weixin-login.imageset/Contents.json
vendored
Normal file
21
ios/PushDeer-iOS/PushDeer/Assets.xcassets/Images/weixin-login.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "微信LOGO_轮廓.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
ios/PushDeer-iOS/PushDeer/Assets.xcassets/Images/weixin-login.imageset/微信LOGO_轮廓.png
vendored
Normal file
BIN
ios/PushDeer-iOS/PushDeer/Assets.xcassets/Images/weixin-login.imageset/微信LOGO_轮廓.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
24
ios/PushDeer-iOS/PushDeer/Common/SafariView.swift
Normal file
24
ios/PushDeer-iOS/PushDeer/Common/SafariView.swift
Normal file
@ -0,0 +1,24 @@
|
||||
//
|
||||
// SafariView.swift
|
||||
// PushDeer
|
||||
//
|
||||
// Created by HEXT on 2022/2/27.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SafariServices
|
||||
|
||||
struct SafariView: UIViewControllerRepresentable {
|
||||
|
||||
let url: URL
|
||||
|
||||
func makeUIViewController(context: Context) -> SFSafariViewController {
|
||||
let safariVC = SFSafariViewController.init(url: url)
|
||||
safariVC.dismissButtonStyle = .close
|
||||
return safariVC
|
||||
}
|
||||
|
||||
func updateUIViewController(_ uiViewController: SFSafariViewController, context: Context) {
|
||||
// update code
|
||||
}
|
||||
}
|
@ -21,4 +21,9 @@ struct Env {
|
||||
static let onlineApiEndpoint = "https://api2.pushdeer.com"
|
||||
/// AppStore 的 appId, 自建版: 1608017631; 在线版: 1596771139
|
||||
static let appStoreId = isSelfHosted ? 1608017631 : 1596771139
|
||||
/// 微信开发者ID
|
||||
static let wxAppid = "wx3ae07931d0555a24"
|
||||
/// 微信开发者Universal Link
|
||||
static let wxUniversalLink = "https://vip.pushdeer.com/app/"
|
||||
|
||||
}
|
||||
|
@ -2,8 +2,26 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>weixin</string>
|
||||
<string>weixinULAPI</string>
|
||||
</array>
|
||||
<key>CFBundleAllowMixedLocalizations</key>
|
||||
<true/>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>weixin</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>wx3ae07931d0555a24</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
|
@ -22,9 +22,9 @@ struct TokenContent: Codable{
|
||||
|
||||
struct UserInfoContent: Codable{
|
||||
let id: Int
|
||||
let name: String
|
||||
let name: String?
|
||||
let email: String?
|
||||
let apple_id: String
|
||||
let apple_id: String?
|
||||
let wechat_id: String?
|
||||
let level: Int
|
||||
let created_at: String
|
||||
@ -74,7 +74,7 @@ struct ActionContent: Codable{
|
||||
let message: String
|
||||
}
|
||||
|
||||
struct PushResultContent: Codable{
|
||||
struct ResultContent: Codable{
|
||||
let result: Array<String>
|
||||
}
|
||||
|
||||
|
7
ios/PushDeer-iOS/PushDeer/PushDeer-Bridging-Header.h
Normal file
7
ios/PushDeer-iOS/PushDeer/PushDeer-Bridging-Header.h
Normal file
@ -0,0 +1,7 @@
|
||||
//
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
#if __has_include("WXApi.h")
|
||||
#import "WXApi.h"
|
||||
#endif
|
@ -11,6 +11,7 @@
|
||||
<key>com.apple.developer.associated-domains</key>
|
||||
<array>
|
||||
<string>appclips:vip.pushdeer.com</string>
|
||||
<string>applinks:vip.pushdeer.com</string>
|
||||
</array>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
|
@ -16,6 +16,18 @@ struct PushDeerApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
.onOpenURL(perform: { url in
|
||||
print(#function, url)
|
||||
#if !targetEnvironment(macCatalyst) && !APPCLIP && !SELFHOSTED
|
||||
WXApi.handleOpen(url, delegate: WXDelegate.shared)
|
||||
#endif
|
||||
})
|
||||
.onContinueUserActivity(NSUserActivityTypeBrowsingWeb, perform: { userActivity in
|
||||
print(#function, userActivity.webpageURL as Any)
|
||||
#if !targetEnvironment(macCatalyst) && !APPCLIP && !SELFHOSTED
|
||||
WXApi.handleOpenUniversalLink(userActivity, delegate: WXDelegate.shared)
|
||||
#endif
|
||||
})
|
||||
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
|
||||
// 后台进入前台后, 清空未读消息角标
|
||||
UIApplication.shared.applicationIconBadgeNumber = 0
|
||||
|
@ -37,6 +37,12 @@ class AppState: ObservableObject {
|
||||
UserDefaults.standard.set(isShowTestPush, forKey: "PushDeer_isShowTestPush")
|
||||
}
|
||||
}
|
||||
/// 是否使用内置浏览器打开链接
|
||||
@Published var isUseBuiltInBrowser: Bool {
|
||||
didSet {
|
||||
UserDefaults.standard.set(isUseBuiltInBrowser, forKey: "PushDeer_isUseBuiltInBrowser")
|
||||
}
|
||||
}
|
||||
|
||||
/// API endpoint
|
||||
@Published var api_endpoint : String {
|
||||
@ -59,10 +65,12 @@ class AppState: ObservableObject {
|
||||
let _token = UserDefaults.standard.string(forKey: "PushDeer_token")
|
||||
let _tabSelectedIndex = UserDefaults.standard.integer(forKey: "PushDeer_tabSelectedIndex")
|
||||
let _isShowTestPush = UserDefaults.standard.object(forKey: "PushDeer_isShowTestPush")
|
||||
let _isUseBuiltInBrowser = UserDefaults.standard.object(forKey: "PushDeer_isUseBuiltInBrowser")
|
||||
let _api_endpoint = UserDefaults.standard.string(forKey: "PushDeer_api_endpoint")
|
||||
token = _token ?? ""
|
||||
tabSelectedIndex = _tabSelectedIndex
|
||||
isShowTestPush = _isShowTestPush as? Bool ?? true
|
||||
isUseBuiltInBrowser = _isUseBuiltInBrowser as? Bool ?? true
|
||||
api_endpoint = _api_endpoint ?? ""
|
||||
}
|
||||
|
||||
@ -97,6 +105,10 @@ class AppState: ObservableObject {
|
||||
}
|
||||
case let .failure(error):
|
||||
print(error)
|
||||
if (error as NSError).code == 1001 {
|
||||
// Apple 登录取消
|
||||
throw NSError(domain: NSLocalizedString("登录失败", comment: "AppleId登录失败时提示") + "\n\(error.localizedDescription)", code: 1001, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("你已取消授权", comment: "")])
|
||||
}
|
||||
// Apple 登录失败
|
||||
throw NSError(domain: NSLocalizedString("登录失败", comment: "AppleId登录失败时提示") + "\n\(error.localizedDescription)", code: -2, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("登录失败", comment: "AppleId登录失败时提示") + "(-2)\n\(error.localizedDescription)"])
|
||||
}
|
||||
|
@ -20,6 +20,12 @@ struct HttpRequest {
|
||||
switch result {
|
||||
case let .success(response):
|
||||
do {
|
||||
print(response)
|
||||
if response.statusCode != 200 {
|
||||
continuation.resume(throwing: NSError(domain: NSLocalizedString("接口报错", comment: "接口报错时提示"), code: response.statusCode, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("接口报错", comment: "接口报错时提示") + "(\(response.statusCode)"]))
|
||||
return
|
||||
}
|
||||
print((try? response.mapJSON()) ?? "返回值解析失败")
|
||||
let result = try JSONDecoder().decode(ApiResult<T>.self, from: response.data)
|
||||
print(result)
|
||||
if let content = result.content, result.code == 0 {
|
||||
@ -50,6 +56,19 @@ struct HttpRequest {
|
||||
return try await request(.login(idToken: idToken), resultType: TokenContent.self)
|
||||
}
|
||||
|
||||
static func wechatLogin(code: String) async throws -> TokenContent {
|
||||
return try await request(.wechatLogin(code: code), resultType: TokenContent.self)
|
||||
}
|
||||
|
||||
/// 合并用户并将旧用户删除
|
||||
/// | 参数 | 说明 |
|
||||
/// | - | - |
|
||||
/// | type | 字符串,必须为 apple 或者 wechat |
|
||||
/// | tokenorcode | type 为 apple时此字段为 idToken,否则为 微信code |
|
||||
static func mergeUser(type: String, tokenorcode: String) async throws -> ResultContent {
|
||||
return try await request(.mergeUser(token: AppState.shared.token, type: type, tokenorcode: tokenorcode), resultType: ResultContent.self)
|
||||
}
|
||||
|
||||
static func getUserInfo() async throws -> UserInfoContent {
|
||||
return try await request(.getUserInfo(token: AppState.shared.token), resultType: UserInfoContent.self)
|
||||
}
|
||||
@ -105,8 +124,8 @@ struct HttpRequest {
|
||||
}
|
||||
}
|
||||
|
||||
static func push(pushkey: String, text: String, desp: String, type: String) async throws -> PushResultContent {
|
||||
return try await request(.push(pushkey: pushkey, text: text, desp: desp, type: type), resultType: PushResultContent.self)
|
||||
static func push(pushkey: String, text: String, desp: String, type: String) async throws -> ResultContent {
|
||||
return try await request(.push(pushkey: pushkey, text: text, desp: desp, type: type), resultType: ResultContent.self)
|
||||
}
|
||||
|
||||
static func getMessages() async throws -> MessageContent {
|
||||
|
@ -11,7 +11,17 @@ import Moya
|
||||
enum PushDeerApi {
|
||||
|
||||
case fake
|
||||
/// 通过苹果 idToken 登入
|
||||
case login(idToken: String)
|
||||
/// 通过微信 oauth code 登入
|
||||
case wechatLogin(code: String)
|
||||
/// 合并用户并将旧用户删除
|
||||
/// | 参数 | 说明 |
|
||||
/// | - | - |
|
||||
/// | token | 认证token |
|
||||
/// | type | 字符串,必须为 apple 或者 wechat |
|
||||
/// | tokenorcode | type 为 apple时此字段为 idToken,否则为 微信code |
|
||||
case mergeUser(token: String, type: String, tokenorcode: String)
|
||||
case getUserInfo(token: String)
|
||||
|
||||
case regDevice(token: String, name: String, device_id: String, is_clip: Int)
|
||||
@ -47,6 +57,10 @@ extension PushDeerApi: TargetType {
|
||||
return "/login/fake"
|
||||
case .login:
|
||||
return "/login/idtoken"
|
||||
case .wechatLogin:
|
||||
return "/login/wecode"
|
||||
case .mergeUser:
|
||||
return "/user/merge"
|
||||
case .getUserInfo:
|
||||
return "/user/info"
|
||||
|
||||
@ -91,6 +105,10 @@ extension PushDeerApi: TargetType {
|
||||
return .requestParameters(parameters: [:], encoding: URLEncoding.queryString)
|
||||
case let .login(idToken):
|
||||
return .requestParameters(parameters: ["idToken": idToken], encoding: URLEncoding.queryString)
|
||||
case let .wechatLogin(code):
|
||||
return .requestParameters(parameters: ["code": code], encoding: URLEncoding.queryString)
|
||||
case let .mergeUser(token, type, tokenorcode):
|
||||
return .requestParameters(parameters: ["token": token, "type": type, "tokenorcode": tokenorcode], encoding: URLEncoding.queryString)
|
||||
case let .getUserInfo(token):
|
||||
return .requestParameters(parameters: ["token": token], encoding: URLEncoding.queryString)
|
||||
|
||||
|
57
ios/PushDeer-iOS/PushDeer/Service/WXDelegate.swift
Normal file
57
ios/PushDeer-iOS/PushDeer/Service/WXDelegate.swift
Normal file
@ -0,0 +1,57 @@
|
||||
//
|
||||
// WXDelegate.swift
|
||||
// PushDeer
|
||||
//
|
||||
// Created by HEXT on 2022/2/26.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
#if !targetEnvironment(macCatalyst) && !APPCLIP && !SELFHOSTED
|
||||
|
||||
@MainActor
|
||||
class WXDelegate: NSObject, WXApiDelegate {
|
||||
|
||||
static let shared = WXDelegate()
|
||||
private override init() { super.init() }
|
||||
|
||||
func onReq(_ req: BaseReq) {
|
||||
print(#function, req.type, req.openID)
|
||||
}
|
||||
func onResp(_ resp: BaseResp) {
|
||||
print(#function, resp.type, resp.errCode, resp.errStr)
|
||||
if let resp = resp as? SendAuthResp { // 是登录授权的响应
|
||||
print(resp.code as Any, resp.state as Any, resp.lang as Any, resp.country as Any)
|
||||
switch resp.errCode {
|
||||
case 0: // 用户同意
|
||||
if let code = resp.code, let state = resp.state {
|
||||
Task {
|
||||
do {
|
||||
if state == "login" {
|
||||
AppState.shared.token = try await HttpRequest.wechatLogin(code: code).token
|
||||
// 给 AppState 的 token 赋值后, SwiftUI 写的 ContentView 页面会监听到并自动进入主页
|
||||
} else if state == "bind" {
|
||||
_ = try await HttpRequest.mergeUser(type: "wechat", tokenorcode: code)
|
||||
// 合并成功, 更新数据
|
||||
AppState.shared.userInfo = try await HttpRequest.getUserInfo()
|
||||
}
|
||||
} catch {
|
||||
HToast.showError(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
case -2: // 用户取消
|
||||
HToast.showWarning(NSLocalizedString("你已取消授权", comment: ""))
|
||||
break
|
||||
case -4: // 用户拒绝授权
|
||||
HToast.showError(NSLocalizedString("你已拒绝授权", comment: ""))
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -15,9 +15,16 @@ struct EditableText: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
TextField(placeholder, text: $value, onCommit: {
|
||||
print("修改文本:", value)
|
||||
TextField(placeholder, text: $value, onEditingChanged: { focus in
|
||||
print("focus", focus, placeholder, value)
|
||||
if !focus {
|
||||
// 输入框失去焦点的时候也保存
|
||||
self.onCommit(value)
|
||||
}
|
||||
}, onCommit: {
|
||||
// enter回车键也会收键盘, 使其失去焦点
|
||||
// print("修改文本:", value)
|
||||
// self.onCommit(value)
|
||||
})
|
||||
.font(.system(size: 20))
|
||||
.foregroundColor(Color.accentColor)
|
||||
|
@ -9,7 +9,7 @@ import SwiftUI
|
||||
|
||||
/// 每个设备项的 View
|
||||
struct DeviceItemView: View {
|
||||
let deviceItem: DeviceItem
|
||||
@State var deviceItem: DeviceItem
|
||||
@EnvironmentObject private var store: AppState
|
||||
|
||||
var body: some View {
|
||||
@ -30,10 +30,14 @@ struct DeviceItemView: View {
|
||||
.padding(EdgeInsets(top: 0, leading: 18, bottom: 0, trailing: 8))
|
||||
|
||||
EditableText(placeholder: NSLocalizedString("输入设备名称", comment: ""), value: deviceItem.name) { value in
|
||||
if deviceItem.name == value {
|
||||
return
|
||||
}
|
||||
Task {
|
||||
// 调用接口修改
|
||||
_ = try await HttpRequest.renameDevice(id: deviceItem.id, name: value)
|
||||
HToast.showSuccess(NSLocalizedString("已修改设备名称", comment: ""))
|
||||
deviceItem.name = value
|
||||
// 在此 Item 在列表中的下标
|
||||
let index = store.devices.firstIndex { $0.id == deviceItem.id }
|
||||
if let index = index {
|
||||
@ -44,7 +48,7 @@ struct DeviceItemView: View {
|
||||
}
|
||||
Text(getInfo(deviceItem: deviceItem))
|
||||
.font(.system(size: 20))
|
||||
Spacer()
|
||||
Spacer(minLength: 12)
|
||||
}
|
||||
.frame(height: 80)
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import SwiftUI
|
||||
|
||||
/// 每个 Key 项的 View
|
||||
struct KeyItemView: View {
|
||||
let keyItem: KeyItem
|
||||
@State var keyItem: KeyItem
|
||||
@EnvironmentObject private var store: AppState
|
||||
|
||||
var body: some View {
|
||||
@ -20,10 +20,14 @@ struct KeyItemView: View {
|
||||
.scaledToFit()
|
||||
.frame(width: 38, height: 38)
|
||||
EditableText(placeholder: NSLocalizedString("输入key名称", comment: ""), value: keyItem.name) { value in
|
||||
if keyItem.name == value {
|
||||
return
|
||||
}
|
||||
Task {
|
||||
// 调用接口修改
|
||||
_ = try await HttpRequest.renameKey(id: keyItem.id, name: value)
|
||||
HToast.showSuccess(NSLocalizedString("已修改key名称", comment: ""))
|
||||
keyItem.name = value
|
||||
// 在此 keyItem 在列表中的下标
|
||||
let index = store.keys.firstIndex { $0.id == keyItem.id }
|
||||
if let index = index {
|
||||
|
@ -31,6 +31,7 @@ struct LoginView: View {
|
||||
.scaleEffect(1.5)
|
||||
.frame(height: 64)
|
||||
} else {
|
||||
// 苹果登录按钮
|
||||
AppleSignInButton(
|
||||
onRequest: { request in
|
||||
request.requestedScopes = [.fullName, .email]
|
||||
@ -42,6 +43,11 @@ struct LoginView: View {
|
||||
// 获取成功去主页
|
||||
} catch {
|
||||
showLoading = false
|
||||
if (error as NSError).code == 1001 {
|
||||
// 取消登录
|
||||
HToast.showWarning(error.localizedDescription)
|
||||
return
|
||||
}
|
||||
HToast.showError(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
@ -49,6 +55,37 @@ struct LoginView: View {
|
||||
.overlay(RoundedRectangle(cornerRadius: 6).stroke(Color.white))
|
||||
.frame(maxWidth: 375, minHeight: 64, maxHeight: 64)
|
||||
.padding()
|
||||
|
||||
#if !targetEnvironment(macCatalyst) && !APPCLIP && !SELFHOSTED
|
||||
if WXApi.isWXAppInstalled() {
|
||||
// 微信登录按钮
|
||||
Button {
|
||||
let req = SendAuthReq()
|
||||
req.scope = "snsapi_userinfo";
|
||||
req.state = "login";
|
||||
WXApi.send(req) { b in
|
||||
print("WXApi.send:", b)
|
||||
}
|
||||
// 微信登录请求发出去后面的逻辑在 AppDelegate 的 onResp 回调方法中处理
|
||||
} label: {
|
||||
HStack {
|
||||
Image("weixin-login")
|
||||
.resizable()
|
||||
.renderingMode(.template)
|
||||
.scaledToFit()
|
||||
.frame(height:20)
|
||||
Text("通过微信登录")
|
||||
}
|
||||
.font(.system(size: 26, weight: .semibold))
|
||||
.foregroundColor(Color("weixinFgColor"))
|
||||
.frame(maxWidth: 375, minHeight: 64, maxHeight: 64)
|
||||
}
|
||||
.background(Color("weixinBgColor"))
|
||||
.cornerRadius(6)
|
||||
.overlay(RoundedRectangle(cornerRadius: 6).stroke(Color("weixinFgColor")))
|
||||
.padding()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
|
@ -44,33 +44,88 @@ struct MessageItemView: View {
|
||||
}
|
||||
}
|
||||
|
||||
extension URL: Identifiable {
|
||||
public var id: Self { self }
|
||||
}
|
||||
|
||||
struct MessageContentView: View {
|
||||
let messageItem: MessageModel
|
||||
@EnvironmentObject private var store: AppState
|
||||
@State private var image: PlatformImage? = nil
|
||||
@State private var showUrl: URL?
|
||||
@State private var showActionSheet = false
|
||||
|
||||
var body: some View {
|
||||
switch messageItem.type {
|
||||
case "markdown":
|
||||
CardView {
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Markdown(Document(messageItem.text ?? ""))
|
||||
Markdown(messageItem.text ?? "")
|
||||
.markdownStyle(
|
||||
DefaultMarkdownStyle(
|
||||
MarkdownStyle(
|
||||
font: .system(size: 14),
|
||||
foregroundColor: UIColor(named: "textColor") ?? UIColor.darkGray
|
||||
foregroundColor: .init("textColor")
|
||||
)
|
||||
)
|
||||
#if !targetEnvironment(macCatalyst)
|
||||
.onOpenMarkdownLink { url in
|
||||
if store.isUseBuiltInBrowser {
|
||||
showUrl = url
|
||||
} else {
|
||||
UIApplication.shared.open(url, options: [:], completionHandler: nil)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if !(messageItem.desp?.isEmpty ?? true) {
|
||||
Markdown(Document(messageItem.desp!))
|
||||
Markdown(messageItem.desp ?? "")
|
||||
.markdownStyle(
|
||||
DefaultMarkdownStyle(
|
||||
MarkdownStyle(
|
||||
font: .system(size: 14),
|
||||
foregroundColor: UIColor(named: "textColor") ?? UIColor.darkGray
|
||||
foregroundColor: .init("textColor")
|
||||
)
|
||||
)
|
||||
#if !targetEnvironment(macCatalyst)
|
||||
.onOpenMarkdownLink { url in
|
||||
if store.isUseBuiltInBrowser {
|
||||
showUrl = url
|
||||
} else {
|
||||
UIApplication.shared.open(url, options: [:], completionHandler: nil)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
#if targetEnvironment(macCatalyst)
|
||||
.contextMenu {
|
||||
Button {
|
||||
UIPasteboard.general.string = (messageItem.text ?? "") + "\n" + (messageItem.desp ?? "")
|
||||
HToast.showSuccess(NSLocalizedString("已复制", comment: ""))
|
||||
} label: {
|
||||
Label("复制",systemImage: "doc.on.doc")
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if !targetEnvironment(macCatalyst)
|
||||
.onLongPressGesture {
|
||||
UIImpactFeedbackGenerator().impactOccurred()
|
||||
showActionSheet = true
|
||||
}
|
||||
.actionSheet(isPresented: $showActionSheet) {
|
||||
ActionSheet(title: Text("复制消息内容"), message: nil, buttons: [
|
||||
.default(Text("复制"), action: {
|
||||
UIPasteboard.general.string = (messageItem.text ?? "") + "\n" + (messageItem.desp ?? "")
|
||||
HToast.showSuccess(NSLocalizedString("已复制", comment: ""))
|
||||
}),
|
||||
.cancel()
|
||||
])
|
||||
}
|
||||
#endif
|
||||
}
|
||||
.fullScreenCover(item: $showUrl) {
|
||||
|
||||
} content: { url in
|
||||
SafariView(url: url)
|
||||
}
|
||||
|
||||
case "image":
|
||||
@ -146,7 +201,7 @@ struct MessageContentView: View {
|
||||
.padding()
|
||||
.contextMenu {
|
||||
Button {
|
||||
UIPasteboard.general.string = (messageItem.text ?? "") + (messageItem.desp ?? "")
|
||||
UIPasteboard.general.string = (messageItem.text ?? "") + "\n" + (messageItem.desp ?? "")
|
||||
HToast.showSuccess(NSLocalizedString("已复制", comment: ""))
|
||||
} label: {
|
||||
Label("复制",systemImage: "doc.on.doc")
|
||||
|
@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import AuthenticationServices
|
||||
//import StoreKit
|
||||
|
||||
/// 设置界面
|
||||
@ -21,6 +22,14 @@ struct SettingsView: View {
|
||||
}
|
||||
.padding(EdgeInsets(top: 18, leading: 20, bottom: 0, trailing: 20))
|
||||
|
||||
#if !targetEnvironment(macCatalyst) && !APPCLIP && !SELFHOSTED
|
||||
if WXApi.isWXAppInstalled() {
|
||||
LoginInfoView()
|
||||
.zIndex(-1)
|
||||
.padding(EdgeInsets(top: -30, leading: 20, bottom: 0, trailing: 20))
|
||||
}
|
||||
#endif
|
||||
|
||||
if Env.isSelfHosted {
|
||||
SettingsItemView(title: NSLocalizedString("API endpoint", comment: ""), button: NSLocalizedString("重置", comment: "")) {
|
||||
store.api_endpoint = ""
|
||||
@ -37,6 +46,22 @@ struct SettingsView: View {
|
||||
}
|
||||
.padding(EdgeInsets(top: 18, leading: 20, bottom: 0, trailing: 20))
|
||||
|
||||
#if !targetEnvironment(macCatalyst)
|
||||
CardView {
|
||||
HStack{
|
||||
Toggle(isOn: $store.isUseBuiltInBrowser) {
|
||||
Text("使用内置浏览器打开链接")
|
||||
.font(.system(size: 18))
|
||||
.foregroundColor(Color("textColor"))
|
||||
}
|
||||
.padding(16)
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
}
|
||||
.frame(height: 74)
|
||||
}
|
||||
.padding(EdgeInsets(top: 18, leading: 20, bottom: 0, trailing: 20))
|
||||
#endif
|
||||
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
@ -64,6 +89,122 @@ struct SettingsView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct LoginInfoView: View {
|
||||
enum AlertType : Identifiable {
|
||||
var id: Self { self }
|
||||
case apple
|
||||
case wechat
|
||||
}
|
||||
@EnvironmentObject private var store: AppState
|
||||
@State private var alertType: AlertType? = nil
|
||||
static private var coordinator: AppleSignInCoordinator? = nil
|
||||
var body: some View {
|
||||
CardView {
|
||||
HStack(spacing: 16) {
|
||||
Spacer()
|
||||
Circle()
|
||||
.frame(width: 10, height: 10, alignment: .center)
|
||||
.foregroundColor(store.userInfo?.apple_id?.isEmpty ?? true ? .gray : .green)
|
||||
Button {
|
||||
if store.userInfo?.apple_id?.isEmpty ?? true {
|
||||
alertType = .apple
|
||||
} else {
|
||||
HToast.showText(NSLocalizedString("当前已经绑定苹果账号", comment: ""))
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "applelogo")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame( height: 40, alignment: .center)
|
||||
}
|
||||
Spacer()
|
||||
Circle()
|
||||
.frame(width: 10, height: 10, alignment: .center)
|
||||
.foregroundColor(store.userInfo?.wechat_id?.isEmpty ?? true ? .gray : .green)
|
||||
Button {
|
||||
if store.userInfo?.wechat_id?.isEmpty ?? true {
|
||||
alertType = .wechat
|
||||
} else {
|
||||
HToast.showText(NSLocalizedString("当前已经绑定微信账号", comment: ""))
|
||||
}
|
||||
} label: {
|
||||
Image("weixin-login")
|
||||
.resizable()
|
||||
.renderingMode(.template)
|
||||
.scaledToFit()
|
||||
.frame(height: 37, alignment: .center)
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding(EdgeInsets(top: 32, leading: 0, bottom: 12, trailing: 0))
|
||||
}
|
||||
.alert(item: $alertType) { alertType in
|
||||
var message = ""
|
||||
switch alertType {
|
||||
case .apple:
|
||||
message = NSLocalizedString("准备绑定苹果账号, 如果你绑定的账号之前已经存在, 则会合并到当前账号. (之前的Key可能会被删除)", comment: "")
|
||||
case .wechat:
|
||||
message = NSLocalizedString("准备绑定微信账号, 如果你绑定的账号之前已经存在, 则会合并到当前账号. (之前的Key可能会被删除)", comment: "")
|
||||
}
|
||||
|
||||
return Alert(
|
||||
title: Text("温馨提示"),
|
||||
message: Text(message),
|
||||
primaryButton: .default(
|
||||
Text("绑定"),
|
||||
action: {
|
||||
switch alertType {
|
||||
case .apple:
|
||||
LoginInfoView.coordinator = AppleSignInCoordinator(
|
||||
onRequest: { request in
|
||||
request.requestedScopes = [.fullName, .email]
|
||||
},
|
||||
onCompletion: { result in
|
||||
do {
|
||||
switch result {
|
||||
case let .success(authorization):
|
||||
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
|
||||
let idToken = String(data:appleIDCredential.identityToken!, encoding: .utf8)
|
||||
print(idToken as Any)
|
||||
// 请求接口
|
||||
let result = try await HttpRequest.mergeUser(type: "apple", tokenorcode: idToken!)
|
||||
print(result)
|
||||
// 合并成功, 更新数据
|
||||
store.userInfo = try await HttpRequest.getUserInfo()
|
||||
}
|
||||
case let .failure(error):
|
||||
if (error as NSError).code == 1001 {
|
||||
HToast.showWarning(NSLocalizedString("你已取消授权", comment: ""))
|
||||
} else {
|
||||
HToast.showError(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
HToast.showError(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
)
|
||||
LoginInfoView.coordinator?.performRequests()
|
||||
|
||||
case .wechat:
|
||||
#if !targetEnvironment(macCatalyst) && !APPCLIP && !SELFHOSTED
|
||||
let req = SendAuthReq()
|
||||
req.scope = "snsapi_userinfo";
|
||||
req.state = "bind";
|
||||
WXApi.send(req) { b in
|
||||
print("WXApi.send:", b)
|
||||
}
|
||||
// 微信登录请求发出去后面的逻辑在 AppDelegate 的 onResp 回调方法中处理
|
||||
#endif
|
||||
}
|
||||
}
|
||||
),
|
||||
secondaryButton: .cancel(Text("稍后"))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SettingsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
SettingsView().environmentObject(AppState.shared)
|
||||
|
@ -1,6 +1,9 @@
|
||||
/* 在设备列表中标识当前设备 */
|
||||
"(当前设备)" = "(current device)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"绑定" = "Bind";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"保存" = "Save";
|
||||
|
||||
@ -16,6 +19,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"标题" = "Title";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"当前已经绑定苹果账号" = "Apple account is currently bound";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"当前已经绑定微信账号" = "WeChat account is currently bound";
|
||||
|
||||
/* token失效时提示 */
|
||||
"登录过期" = "Login expired";
|
||||
|
||||
@ -46,6 +55,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"你还未注册当前设备, 注册后才能收到推送, 是否现在注册? (你还可以稍后点击右上角 + 符号添加当前设备)" = "You have not registered the current device, you can receive push notifications after registration, do you want to register now? (You can also click the + symbol in the upper right corner to add the current device later)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"你已拒绝授权" = "You have denied authorization";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"你已取消授权" = "You have deauthorized";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"您在此应用中的数据都将发送到 endpoint 指向的服务器" = "Your data in this app will be sent to the server pointed to by endpoint";
|
||||
|
||||
@ -79,6 +94,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"设置" = "Settings";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"使用内置浏览器打开链接" = "Open links using built-in browser";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"输入设备名称" = "Enter device name";
|
||||
|
||||
@ -86,7 +104,7 @@
|
||||
"输入key名称" = "Enter key name";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"温馨提示" = "Tips";
|
||||
"通过微信登录" = "Sign in with WeChat";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"图片未加载成功" = "Image did not load successfully";
|
||||
@ -106,6 +124,9 @@
|
||||
/* 退出登录按钮上的文字 */
|
||||
"退出" = "Logout";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"温馨提示" = "Tips";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"喜欢PushDeer?" = "Like PushDeer?";
|
||||
|
||||
@ -148,6 +169,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"注册" = "Register";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"准备绑定苹果账号, 如果你绑定的账号之前已经存在, 则会合并到当前账号. (之前的Key可能会被删除)" = "Prepare to bind the Apple account. If the account you bind already exists, it will be merged into the current account. (The previous Key may be deleted)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"准备绑定微信账号, 如果你绑定的账号之前已经存在, 则会合并到当前账号. (之前的Key可能会被删除)" = "Prepare to bind the WeChat account. If the account you bind already exists, it will be merged into the current account. (The previous Key may be deleted)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"自定义服务器" = "Custom server";
|
||||
|
||||
@ -157,3 +184,5 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Endpoint 格式不正确" = "Endpoint is malformed";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"复制消息内容" = "Copy message content";
|
||||
|
447
ios/PushDeer-iOS/remove_unsupported_libraries.rb
Normal file
447
ios/PushDeer-iOS/remove_unsupported_libraries.rb
Normal file
@ -0,0 +1,447 @@
|
||||
###### CONSISTENCY BETWEEN MACOS AND IOS #####
|
||||
#
|
||||
# In order to use the same PodFile with MacOS, we need to unlink the libraries that do not support Catalyst, filter
|
||||
# files in native targets build phases, filter dependencies and make sure the unsupported frameworks along with their
|
||||
# their bundle resources are not included in the final archive. For that, we use `platform_filter` to specify 'ios' and
|
||||
# 'OTHER_LDFLAGS[sdk=iphone*]' to link those libraries for iPhone and iPad. Besides, we modify "*frameworks.sh" and
|
||||
# "*resrouces.sh" to skip installation for architecture x86_64.
|
||||
#
|
||||
# *Notice*: 'sdk=iphone*' excludes macOS, even though Catalyst is compiled with iOS SDK.
|
||||
#
|
||||
# ADDING A NEW LIBRARY
|
||||
#
|
||||
# Pass the name of the new library to the script
|
||||
#
|
||||
###### RESOURCES #######
|
||||
#
|
||||
# https://www.bitbuildr.com/tech-blog/mac-catalyst-porting-an-app-using-crashlytics-firebase - Article that inspired this script
|
||||
# https://github.com/CocoaPods/Xcodeproj - Xcode configuration using ruby. This Framework is already included on cocoapods environment
|
||||
# https://www.rubydoc.info/gems/xcodeproj/Xcodeproj/Project/Object/AbstractTarget Wiki for Xcodeproj
|
||||
#
|
||||
|
||||
include Xcodeproj::Project::Object
|
||||
include Pod
|
||||
|
||||
$verbose = false
|
||||
|
||||
def loggs string
|
||||
if $verbose
|
||||
puts string
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# EXTENSIONS
|
||||
|
||||
class String
|
||||
def filter_lines
|
||||
lines = []
|
||||
each_line do |line|
|
||||
if yield line
|
||||
lines = lines + [line]
|
||||
end
|
||||
end
|
||||
return lines
|
||||
end
|
||||
end
|
||||
|
||||
class PBXNativeTarget
|
||||
|
||||
###### STEP 4 ######
|
||||
# In "Pods-" targets, modify "*frameworks.sh" to not install unsupported frameworks for platform architectures
|
||||
def uninstall_frameworks frameworks, platform, configurations
|
||||
uninstall frameworks, "#{name}-frameworks.sh", platform.architectures, configurations
|
||||
end
|
||||
|
||||
###### STEP 5 ######
|
||||
# In "Pods-" targets, modify "*resources.sh" to not install unsupported frameworks for platform architectures
|
||||
def uninstall_resources resources, platform, configurations
|
||||
uninstall resources, "#{name}-resources.sh", platform.architectures, configurations
|
||||
end
|
||||
|
||||
def support_files_folder
|
||||
build_configurations.filter do |config| not config.base_configuration_reference.nil? end.first.base_configuration_reference.real_path.parent
|
||||
end
|
||||
|
||||
@private
|
||||
def uninstall keys, file_name, architectures, configurations=nil
|
||||
configurations = configurations.nil? ? build_configurations.map { |b| b.name } : configurations
|
||||
keys = keys.to_set.to_a
|
||||
loggs "\t\t\tUninstalling for configurations: #{configurations}"
|
||||
if support_files_folder.nil?
|
||||
loggs "\t\t\tNothing to uninstall"
|
||||
return
|
||||
end
|
||||
|
||||
script_path = support_files_folder.join file_name
|
||||
if !script_path.exist?
|
||||
loggs "\t\t\tNothing to uninstall"
|
||||
return
|
||||
end
|
||||
|
||||
script = File.read(script_path)
|
||||
snippets = script.scan(/if \[\[ \"\$CONFIGURATION\" [\S\s]*?(?=fi\n)fi/)
|
||||
condition = architectures.map do |arch| "[ \"$ARCHS\" != \"#{arch}\" ]" end.reduce("") do |total, piece| total.empty? ? piece : total + " || " + piece end
|
||||
changed = false
|
||||
|
||||
snippets.filter do |snippet|
|
||||
configurations.map do |string| snippet.include? string end.reduce(false) do |total, condition| total = total || condition end
|
||||
end.each do |snippet|
|
||||
new_snippet = snippet.clone
|
||||
keys.each do |key|
|
||||
lines_to_replace = snippet.filter_lines do |line| line.include? "#{key}" end.to_set.to_a
|
||||
unless lines_to_replace.empty?
|
||||
changed = true
|
||||
lines_to_replace.each do |line|
|
||||
new_snippet.gsub! line, "\tif #{condition}; then \n\t#{line}\tfi\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
script.gsub! snippet, new_snippet
|
||||
end
|
||||
|
||||
if changed
|
||||
File.open(script_path, "w") { |file| file << script }
|
||||
end
|
||||
loggs "\t\t\t#{changed ? "Succeded" : "Nothing to uninstall"}"
|
||||
end
|
||||
|
||||
###### STEP 1 ######
|
||||
# In native target's build phases, add platform filter to:
|
||||
# - Resources
|
||||
# - Compile Sources
|
||||
# - Frameworks
|
||||
# - Headers
|
||||
def add_platform_filter_to_build_phases platform
|
||||
loggs "\t\t- Filtering resources"
|
||||
resources_build_phase.files.to_a.map do |build_file| build_file.platform_filter = platform.name end
|
||||
|
||||
loggs "\t\t- Filtering compile sources"
|
||||
source_build_phase.files.to_a.map do |build_file| build_file.platform_filter = platform.name end
|
||||
|
||||
loggs "\t\t- Filtering frameworks"
|
||||
frameworks_build_phase.files.to_a.map do |build_file| build_file.platform_filter = platform.name end
|
||||
|
||||
loggs "\t\t- Filtering headers"
|
||||
headers_build_phase.files.to_a.map do |build_file| build_file.platform_filter = platform.name end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class PodTarget
|
||||
|
||||
def module_name
|
||||
string = name.clone.gsub! /-iOS[0-9]+(\.[0-9])+$/, ''
|
||||
return string.nil? ? name : string
|
||||
end
|
||||
|
||||
def resources
|
||||
return file_accessors.flat_map do |accessor| accessor.resources end.map do |path| "#{path.basename}" end
|
||||
end
|
||||
|
||||
def vendor_products
|
||||
return file_accessors.flat_map do |accessor|
|
||||
accessor.vendored_frameworks + accessor.vendored_libraries
|
||||
end.map do |s| s.basename
|
||||
end.map do |s|
|
||||
name = "#{s}"
|
||||
if name.include? "framework"
|
||||
PodDependency.newFramework name.sub(".framework", "")
|
||||
else
|
||||
PodDependency.newLibrary name.sub("lib", "").sub(".a", "")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def frameworks
|
||||
return file_accessors.flat_map do |accessor|
|
||||
accessor.spec_consumer.frameworks.map do |name| PodDependency.newFramework name end + accessor.spec_consumer.libraries.map do |name| PodDependency.newLibrary name end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class PBXTargetDependency
|
||||
def module_name
|
||||
string = name.clone.gsub! /-iOS[0-9]+(\.[0-9])+$/, ''
|
||||
return string.nil? ? name : string
|
||||
end
|
||||
end
|
||||
|
||||
class AbstractTarget
|
||||
|
||||
def module_name
|
||||
string = name.clone.gsub! /-iOS[0-9]+(\.[0-9])+$/, ''
|
||||
return string.nil? ? name : string
|
||||
end
|
||||
|
||||
###### STEP 2 ######
|
||||
# In all targets (aggregates + native), filter dependencies
|
||||
def add_platform_filter_to_dependencies platform
|
||||
loggs "\t\t- Filtering dependencies"
|
||||
dependencies.each do |dependency|
|
||||
dependency.platform_filter = platform.name
|
||||
end
|
||||
end
|
||||
|
||||
###### STEP 3 ######
|
||||
# If any unsupported library, then flag as platform-dependant for every build configuration
|
||||
def flag_libraries libraries, platform
|
||||
loggs "\tTarget: #{name}"
|
||||
build_configurations.filter do |config| not config.base_configuration_reference.nil?
|
||||
end.each do |config|
|
||||
loggs "\t\tScheme: #{config.name}"
|
||||
xcconfig_path = config.base_configuration_reference.real_path
|
||||
xcconfig = File.read(xcconfig_path)
|
||||
|
||||
changed = false
|
||||
libraries.each do |framework|
|
||||
if xcconfig.include? framework
|
||||
xcconfig.gsub!(framework, '')
|
||||
unless xcconfig.include? "OTHER_LDFLAGS[sdk=#{platform.sdk}]"
|
||||
changed = true
|
||||
xcconfig += "OTHER_LDFLAGS[sdk=#{platform.sdk}] = $(inherited) -ObjC "
|
||||
end
|
||||
xcconfig += framework + ' '
|
||||
end
|
||||
end
|
||||
|
||||
File.open(xcconfig_path, "w") { |file| file << xcconfig }
|
||||
loggs "\t\t\t#{changed ? "Succeded" : "Nothing to flag"}"
|
||||
end
|
||||
end
|
||||
|
||||
def to_dependency
|
||||
# We return both as we don't know if build as library or framework
|
||||
return [PodDependency.newFramework(module_name), PodDependency.newLibrary(module_name)]
|
||||
end
|
||||
|
||||
# Dependencies contained in Other Linker Flags
|
||||
def other_linker_flags_dependencies
|
||||
frameworks = Array.new
|
||||
libraries = Array.new
|
||||
|
||||
config = build_configurations.filter do |config| not config.base_configuration_reference.nil? end.first
|
||||
xcconfig_path = config.base_configuration_reference.real_path
|
||||
xcconfig = File.read(xcconfig_path)
|
||||
xcconfig.gsub!(/\r\n?/, "\n")
|
||||
|
||||
xcconfig.each_line do |line|
|
||||
if line.start_with? 'OTHER_LDFLAGS'
|
||||
frameworks = frameworks + line.split("-framework").map do |s|
|
||||
s.strip.delete("\n") end.filter do |s|
|
||||
s.strip.start_with? '"' end
|
||||
libraries = libraries + line.split("-l").filter do |s| s.strip.start_with? '"' end.map do |s| s.strip.split(' ').first end
|
||||
end
|
||||
end
|
||||
|
||||
libraries = libraries.map do |name| PodDependency.newLibrary(name.gsub!("\"", "")) end
|
||||
frameworks = frameworks.map do |name| PodDependency.newFramework(name.gsub!("\"", "")) end
|
||||
|
||||
return OtherLinkerFlagsDependencies.new libraries, frameworks
|
||||
end
|
||||
end
|
||||
|
||||
# HELPER CLASSES
|
||||
|
||||
class PodDependency
|
||||
attr_reader :name
|
||||
attr_reader :type
|
||||
|
||||
def link
|
||||
if library?
|
||||
return "-l\"#{name}\""
|
||||
else
|
||||
return "-framework \"#{name}\""
|
||||
end
|
||||
end
|
||||
|
||||
def library?
|
||||
return type == "library"
|
||||
end
|
||||
|
||||
def framework?
|
||||
return type == "framework"
|
||||
end
|
||||
|
||||
def self.newFramework name
|
||||
return PodDependency.new(name, "framework")
|
||||
end
|
||||
|
||||
def self.newLibrary name
|
||||
return PodDependency.new(name, "library")
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
name == other.name && type == other.type
|
||||
end
|
||||
|
||||
def eql?(other)
|
||||
name == other.name
|
||||
end
|
||||
|
||||
private
|
||||
def initialize(name, type)
|
||||
@name = name
|
||||
@type = type
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class OtherLinkerFlagsDependencies
|
||||
attr_reader :libraries
|
||||
attr_reader :frameworks
|
||||
|
||||
def initialize(libraries = [], frameworks = [])
|
||||
@libraries = libraries
|
||||
@frameworks = frameworks
|
||||
end
|
||||
|
||||
def combine dependencies
|
||||
frameworks = (dependencies.frameworks + @frameworks).to_set.to_a
|
||||
libraries = (dependencies.libraries + @libraries).to_set.to_a
|
||||
return OtherLinkerFlagsDependencies.new libraries, frameworks
|
||||
end
|
||||
|
||||
def dependencies
|
||||
libraries + frameworks
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class OSPlatform
|
||||
attr_reader :sdk
|
||||
attr_reader :name
|
||||
attr_reader :architectures
|
||||
|
||||
def self.ios
|
||||
OSPlatform.new 'ios', 'iphone*', ['arm64', 'armv7s', 'armv7']
|
||||
end
|
||||
|
||||
def self.macos
|
||||
OSPlatform.new 'macos', 'macosx*', ['x86_64']
|
||||
end
|
||||
|
||||
def self.wtachos
|
||||
OSPlatform.new 'watchos', 'watchos*', ['arm64_32', 'armv7k']
|
||||
end
|
||||
|
||||
def self.tvos
|
||||
OSPlatform.new 'tvos', 'appletvos*', ['arm64']
|
||||
end
|
||||
|
||||
private
|
||||
def initialize(name, sdk, architectures)
|
||||
@name = name
|
||||
@sdk = sdk
|
||||
@architectures = architectures
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# SCRIPT
|
||||
|
||||
class Installer
|
||||
|
||||
def configure_support_catalyst pod_names_to_keep, pod_names_to_remove, configurations=nil
|
||||
|
||||
###### Variable definition ######
|
||||
targets = pods_project.targets
|
||||
|
||||
pod_names_to_remove = pod_names_to_remove.map do |name| name.sub('/', '') end
|
||||
pod_names_to_keep = pod_names_to_keep.map do |name| name.sub('/', '') end
|
||||
|
||||
pod_names_to_keep = recursive_dependencies pod_names_to_keep
|
||||
pod_names_to_remove = recursive_dependencies(pod_names_to_remove).filter do |name| !pod_names_to_keep.include? name end
|
||||
|
||||
pod_targets_to_keep = pod_targets.filter do |pod| pod_names_to_keep.include? pod.module_name end # PodTarget
|
||||
pod_targets_to_remove = pod_targets.filter do |pod| pod_names_to_remove.include? pod.module_name end # PodTarget
|
||||
|
||||
loggs "\n#### Unsupported Libraries ####\n#{pod_names_to_remove}\n"
|
||||
|
||||
targets_to_remove = targets.filter do |target| pod_names_to_remove.include?(target.module_name) end # AbstractTarget
|
||||
pods_targets = targets.filter do |target| target.name.start_with? "Pods-" end # AbstractTarget
|
||||
cross_platform_targets = targets.filter do |target| !targets_to_remove.include?(target) && !pods_targets.include?(target) end # AbstractTarget
|
||||
|
||||
###### Determine which dependencies should be removed ######
|
||||
dependencies_to_keep = cross_platform_targets.reduce(OtherLinkerFlagsDependencies.new) do |dependencies, target|
|
||||
dependencies.combine target.other_linker_flags_dependencies
|
||||
end.dependencies
|
||||
|
||||
# [PodDependency]
|
||||
dependencies_to_keep = dependencies_to_keep + cross_platform_targets.flat_map do |target| target.to_dependency end + pod_targets_to_keep.flat_map do |pod| pod.vendor_products + pod.frameworks end
|
||||
|
||||
dependencies_to_remove = targets_to_remove.reduce(OtherLinkerFlagsDependencies.new) do |dependencies, target|
|
||||
dependencies.combine target.other_linker_flags_dependencies
|
||||
end.dependencies
|
||||
|
||||
# [PodDependency]
|
||||
dependencies_to_remove = dependencies_to_remove + targets_to_remove.flat_map do |target| target.to_dependency end + pod_targets_to_remove.flat_map do |pod| pod.vendor_products + pod.frameworks end
|
||||
dependencies_to_remove = dependencies_to_remove.filter do |d| !dependencies_to_keep.include? d end
|
||||
|
||||
###### CATALYST NOT SUPPORTED LINKS ######
|
||||
unsupported_links = dependencies_to_remove.map do |d| d.link end.to_set.to_a
|
||||
|
||||
loggs "#### Unsupported dependencies ####\n"
|
||||
loggs "#{dependencies_to_remove.map do |d| d.name end.to_set.to_a }\n\n"
|
||||
|
||||
###### CATALYST NOT SUPPORTED FRAMEWORKS AND RESOURCES
|
||||
frameworks_to_uninstall = dependencies_to_remove.filter do |d| d.framework? end.map do |d| "#{d.name}.framework" end.to_set.to_a
|
||||
resources_to_uninstall = pod_targets_to_remove.flat_map do |pod| pod.resources end.to_set.to_a
|
||||
|
||||
loggs "#### Frameworks not to be included in the Archive ####\n"
|
||||
loggs "#{frameworks_to_uninstall}\n\n"
|
||||
|
||||
loggs "#### Resources not to be included in the Archive ####\n"
|
||||
loggs "#{resources_to_uninstall}\n\n"
|
||||
|
||||
###### OTHER LINKER FLAGS -> to iphone* ######
|
||||
loggs "#### Flagging unsupported libraries ####"
|
||||
targets.each do |target| target.flag_libraries unsupported_links, OSPlatform.ios end
|
||||
|
||||
###### BUILD_PHASES AND DEPENDENCIES -> PLATFORM_FILTER 'ios' ######
|
||||
loggs "\n#### Filtering build phases ####"
|
||||
targets_to_remove.filter do |target|
|
||||
pods_project.native_targets.include? target
|
||||
end.each do |target|
|
||||
loggs "\tTarget: #{target.name}"
|
||||
target.add_platform_filter_to_build_phases OSPlatform.ios
|
||||
target.add_platform_filter_to_dependencies OSPlatform.ios
|
||||
end
|
||||
|
||||
loggs "\n#### Filtering dependencies ####"
|
||||
targets_to_remove.filter do |target|
|
||||
!pods_project.native_targets.include? target
|
||||
end.each do |target|
|
||||
loggs "\tTarget: #{target.name}"
|
||||
target.add_platform_filter_to_dependencies OSPlatform.ios
|
||||
end
|
||||
|
||||
###### FRAMEWORKS AND RESOURCES SCRIPT -> if [ "$ARCHS" != "x86_64" ]; then #######
|
||||
loggs "\n#### Chagings frameworks and resources script ####"
|
||||
pods_targets.each do |target|
|
||||
loggs "\tTarget: #{target.name}"
|
||||
loggs "\t\t-Uninstalling frameworks"
|
||||
target.uninstall_frameworks frameworks_to_uninstall, OSPlatform.macos, configurations
|
||||
|
||||
loggs "\t\t-Uninstalling resources"
|
||||
target.uninstall_resources resources_to_uninstall, OSPlatform.macos, configurations
|
||||
end
|
||||
end
|
||||
|
||||
@private
|
||||
def recursive_dependencies to_filter_names
|
||||
targets = pods_project.targets
|
||||
targets_to_remove = targets.filter do |target| to_filter_names.include? target.module_name end
|
||||
dependencies = targets_to_remove.flat_map do |target| target.dependencies end
|
||||
dependencies_names = dependencies.map do |d| d.module_name end
|
||||
|
||||
if dependencies.empty?
|
||||
return to_filter_names + dependencies_names
|
||||
else
|
||||
return to_filter_names + recursive_dependencies(dependencies_names)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user