登录功能完成
1
Podfile
@ -33,5 +33,6 @@ target 'ReaderHive' do
|
|||||||
pod 'Toast'
|
pod 'Toast'
|
||||||
pod 'SVProgressHUD'
|
pod 'SVProgressHUD'
|
||||||
pod 'FDFullscreenPopGesture'
|
pod 'FDFullscreenPopGesture'
|
||||||
|
pod 'ZLPhotoBrowser'
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -96,6 +96,12 @@
|
|||||||
85CF94292EED4664006467E3 /* NRVipRetainAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94282EED4664006467E3 /* NRVipRetainAlert.swift */; };
|
85CF94292EED4664006467E3 /* NRVipRetainAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94282EED4664006467E3 /* NRVipRetainAlert.swift */; };
|
||||||
85CF942B2EED47F2006467E3 /* NRVipRetainItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF942A2EED47F2006467E3 /* NRVipRetainItemView.swift */; };
|
85CF942B2EED47F2006467E3 /* NRVipRetainItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF942A2EED47F2006467E3 /* NRVipRetainItemView.swift */; };
|
||||||
85CF942D2EED5204006467E3 /* NRPayAlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF942C2EED5204006467E3 /* NRPayAlertModel.swift */; };
|
85CF942D2EED5204006467E3 /* NRPayAlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF942C2EED5204006467E3 /* NRPayAlertModel.swift */; };
|
||||||
|
85CF942F2EEFB2CF006467E3 /* NRLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF942E2EEFB2CF006467E3 /* NRLoginView.swift */; };
|
||||||
|
85CF94312EEFDA88006467E3 /* NRLoginManager+Apple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94302EEFDA82006467E3 /* NRLoginManager+Apple.swift */; };
|
||||||
|
85CF94332EEFDAF4006467E3 /* NRThirdSignModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94322EEFDAF4006467E3 /* NRThirdSignModel.swift */; };
|
||||||
|
85CF94372EEFE27E006467E3 /* FacebookLogin in Frameworks */ = {isa = PBXBuildFile; productRef = 85CF94362EEFE27E006467E3 /* FacebookLogin */; };
|
||||||
|
85CF94392EEFE35A006467E3 /* NRLoginManager+Facebook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94382EEFE34F006467E3 /* NRLoginManager+Facebook.swift */; };
|
||||||
|
85CF943B2EEFE94C006467E3 /* AppDelegate+Open.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF943A2EEFE947006467E3 /* AppDelegate+Open.swift */; };
|
||||||
F34348AF2ED5B85300AA7E70 /* NRExploreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348AE2ED5B85300AA7E70 /* NRExploreViewController.swift */; };
|
F34348AF2ED5B85300AA7E70 /* NRExploreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348AE2ED5B85300AA7E70 /* NRExploreViewController.swift */; };
|
||||||
F34348B12ED5B9A400AA7E70 /* NRExploreNovelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348B02ED5B9A400AA7E70 /* NRExploreNovelViewController.swift */; };
|
F34348B12ED5B9A400AA7E70 /* NRExploreNovelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348B02ED5B9A400AA7E70 /* NRExploreNovelViewController.swift */; };
|
||||||
F34348B32ED5BB6100AA7E70 /* NRExploreNovelMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348B22ED5BB6100AA7E70 /* NRExploreNovelMenuView.swift */; };
|
F34348B32ED5BB6100AA7E70 /* NRExploreNovelMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348B22ED5BB6100AA7E70 /* NRExploreNovelMenuView.swift */; };
|
||||||
@ -327,6 +333,12 @@
|
|||||||
85CF94282EED4664006467E3 /* NRVipRetainAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRVipRetainAlert.swift; sourceTree = "<group>"; };
|
85CF94282EED4664006467E3 /* NRVipRetainAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRVipRetainAlert.swift; sourceTree = "<group>"; };
|
||||||
85CF942A2EED47F2006467E3 /* NRVipRetainItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRVipRetainItemView.swift; sourceTree = "<group>"; };
|
85CF942A2EED47F2006467E3 /* NRVipRetainItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRVipRetainItemView.swift; sourceTree = "<group>"; };
|
||||||
85CF942C2EED5204006467E3 /* NRPayAlertModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRPayAlertModel.swift; sourceTree = "<group>"; };
|
85CF942C2EED5204006467E3 /* NRPayAlertModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRPayAlertModel.swift; sourceTree = "<group>"; };
|
||||||
|
85CF942E2EEFB2CF006467E3 /* NRLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRLoginView.swift; sourceTree = "<group>"; };
|
||||||
|
85CF94302EEFDA82006467E3 /* NRLoginManager+Apple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NRLoginManager+Apple.swift"; sourceTree = "<group>"; };
|
||||||
|
85CF94322EEFDAF4006467E3 /* NRThirdSignModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRThirdSignModel.swift; sourceTree = "<group>"; };
|
||||||
|
85CF94342EEFDFAC006467E3 /* ReaderHive.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ReaderHive.entitlements; sourceTree = "<group>"; };
|
||||||
|
85CF94382EEFE34F006467E3 /* NRLoginManager+Facebook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NRLoginManager+Facebook.swift"; sourceTree = "<group>"; };
|
||||||
|
85CF943A2EEFE947006467E3 /* AppDelegate+Open.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Open.swift"; sourceTree = "<group>"; };
|
||||||
C3BEE224CB3F55939653D26D /* Pods-NovelReader.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NovelReader.debug.xcconfig"; path = "Target Support Files/Pods-NovelReader/Pods-NovelReader.debug.xcconfig"; sourceTree = "<group>"; };
|
C3BEE224CB3F55939653D26D /* Pods-NovelReader.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NovelReader.debug.xcconfig"; path = "Target Support Files/Pods-NovelReader/Pods-NovelReader.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
F34348AE2ED5B85300AA7E70 /* NRExploreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRExploreViewController.swift; sourceTree = "<group>"; };
|
F34348AE2ED5B85300AA7E70 /* NRExploreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRExploreViewController.swift; sourceTree = "<group>"; };
|
||||||
F34348B02ED5B9A400AA7E70 /* NRExploreNovelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRExploreNovelViewController.swift; sourceTree = "<group>"; };
|
F34348B02ED5B9A400AA7E70 /* NRExploreNovelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRExploreNovelViewController.swift; sourceTree = "<group>"; };
|
||||||
@ -469,6 +481,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
85CF94372EEFE27E006467E3 /* FacebookLogin in Frameworks */,
|
||||||
67DC33BD353DB9F2D4C0FFE8 /* Pods_ReaderHive.framework in Frameworks */,
|
67DC33BD353DB9F2D4C0FFE8 /* Pods_ReaderHive.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@ -588,6 +601,7 @@
|
|||||||
03980F862ED009EB0006E317 /* ReaderHive */ = {
|
03980F862ED009EB0006E317 /* ReaderHive */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
85CF94342EEFDFAC006467E3 /* ReaderHive.entitlements */,
|
||||||
03980F8F2ED00ACD0006E317 /* Delegate */,
|
03980F8F2ED00ACD0006E317 /* Delegate */,
|
||||||
039810562ED046030006E317 /* Base */,
|
039810562ED046030006E317 /* Base */,
|
||||||
039810752ED054090006E317 /* Class */,
|
039810752ED054090006E317 /* Class */,
|
||||||
@ -615,6 +629,7 @@
|
|||||||
03980F7D2ED009EB0006E317 /* AppDelegate.swift */,
|
03980F7D2ED009EB0006E317 /* AppDelegate.swift */,
|
||||||
03980F842ED009EB0006E317 /* SceneDelegate.swift */,
|
03980F842ED009EB0006E317 /* SceneDelegate.swift */,
|
||||||
0398107B2ED0551C0006E317 /* AppDelegate+Config.swift */,
|
0398107B2ED0551C0006E317 /* AppDelegate+Config.swift */,
|
||||||
|
85CF943A2EEFE947006467E3 /* AppDelegate+Open.swift */,
|
||||||
);
|
);
|
||||||
path = Delegate;
|
path = Delegate;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -728,8 +743,11 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
0398107E2ED055D10006E317 /* NRLoginManager.swift */,
|
0398107E2ED055D10006E317 /* NRLoginManager.swift */,
|
||||||
|
85CF94302EEFDA82006467E3 /* NRLoginManager+Apple.swift */,
|
||||||
|
85CF94382EEFE34F006467E3 /* NRLoginManager+Facebook.swift */,
|
||||||
039810802ED056090006E317 /* NRLoginToken.swift */,
|
039810802ED056090006E317 /* NRLoginToken.swift */,
|
||||||
039810822ED0563D0006E317 /* NRUserInfo.swift */,
|
039810822ED0563D0006E317 /* NRUserInfo.swift */,
|
||||||
|
85CF94322EEFDAF4006467E3 /* NRThirdSignModel.swift */,
|
||||||
);
|
);
|
||||||
path = Login;
|
path = Login;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1027,6 +1045,7 @@
|
|||||||
F349910A2EE16B520039E939 /* NRAboutCell.swift */,
|
F349910A2EE16B520039E939 /* NRAboutCell.swift */,
|
||||||
F34991172EE1780A0039E939 /* NRNovelHistoryCell.swift */,
|
F34991172EE1780A0039E939 /* NRNovelHistoryCell.swift */,
|
||||||
F3B859382EE676610095A9CC /* NRLanguageCell.swift */,
|
F3B859382EE676610095A9CC /* NRLanguageCell.swift */,
|
||||||
|
85CF942E2EEFB2CF006467E3 /* NRLoginView.swift */,
|
||||||
);
|
);
|
||||||
path = V;
|
path = V;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1222,6 +1241,9 @@
|
|||||||
);
|
);
|
||||||
mainGroup = 03980F5C2ED009E30006E317;
|
mainGroup = 03980F5C2ED009E30006E317;
|
||||||
minimizedProjectReferenceProxies = 1;
|
minimizedProjectReferenceProxies = 1;
|
||||||
|
packageReferences = (
|
||||||
|
85CF94352EEFE27E006467E3 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */,
|
||||||
|
);
|
||||||
preferredProjectObjectVersion = 77;
|
preferredProjectObjectVersion = 77;
|
||||||
productRefGroup = 03980F662ED009E30006E317 /* Products */;
|
productRefGroup = 03980F662ED009E30006E317 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
@ -1299,9 +1321,11 @@
|
|||||||
files = (
|
files = (
|
||||||
F34991252EE27DB60039E939 /* NRGradientButton.swift in Sources */,
|
F34991252EE27DB60039E939 /* NRGradientButton.swift in Sources */,
|
||||||
F34348FD2ED8561300AA7E70 /* NRNovelReadContentBottomView.swift in Sources */,
|
F34348FD2ED8561300AA7E70 /* NRNovelReadContentBottomView.swift in Sources */,
|
||||||
|
85CF94332EEFDAF4006467E3 /* NRThirdSignModel.swift in Sources */,
|
||||||
F34348C52ED6CA4D00AA7E70 /* NRExploreNovelMenuDataSource.swift in Sources */,
|
F34348C52ED6CA4D00AA7E70 /* NRExploreNovelMenuDataSource.swift in Sources */,
|
||||||
F343492A2EDD93AD00AA7E70 /* NRReadSettingFontView.swift in Sources */,
|
F343492A2EDD93AD00AA7E70 /* NRReadSettingFontView.swift in Sources */,
|
||||||
039810982ED066B20006E317 /* NRTool.swift in Sources */,
|
039810982ED066B20006E317 /* NRTool.swift in Sources */,
|
||||||
|
85CF943B2EEFE94C006467E3 /* AppDelegate+Open.swift in Sources */,
|
||||||
F34991272EE2826D0039E939 /* NRNovelReadViewModel+Data.swift in Sources */,
|
F34991272EE2826D0039E939 /* NRNovelReadViewModel+Data.swift in Sources */,
|
||||||
F34348CD2ED6DD0900AA7E70 /* NRNovelGenresCell.swift in Sources */,
|
F34348CD2ED6DD0900AA7E70 /* NRNovelGenresCell.swift in Sources */,
|
||||||
F34348FF2ED85BF200AA7E70 /* NRReadBatteryView.swift in Sources */,
|
F34348FF2ED85BF200AA7E70 /* NRReadBatteryView.swift in Sources */,
|
||||||
@ -1309,6 +1333,7 @@
|
|||||||
039810BA2ED4377E0006E317 /* NRHomeNovelReadWhatCell.swift in Sources */,
|
039810BA2ED4377E0006E317 /* NRHomeNovelReadWhatCell.swift in Sources */,
|
||||||
F3B8596B2EE91C9F0095A9CC /* NRStoreCoinsCell.swift in Sources */,
|
F3B8596B2EE91C9F0095A9CC /* NRStoreCoinsCell.swift in Sources */,
|
||||||
F3B859712EE94A1B0095A9CC /* NRFeedbackViewController.swift in Sources */,
|
F3B859712EE94A1B0095A9CC /* NRFeedbackViewController.swift in Sources */,
|
||||||
|
85CF94392EEFE35A006467E3 /* NRLoginManager+Facebook.swift in Sources */,
|
||||||
F34348C72ED6CCBC00AA7E70 /* NRExploreNovelContentListViewController.swift in Sources */,
|
F34348C72ED6CCBC00AA7E70 /* NRExploreNovelContentListViewController.swift in Sources */,
|
||||||
039810B82ED431780006E317 /* NRHomeNovelReadWhatView.swift in Sources */,
|
039810B82ED431780006E317 /* NRHomeNovelReadWhatView.swift in Sources */,
|
||||||
F34349142EDA9AE900AA7E70 /* NRNovelReadSettingView.swift in Sources */,
|
F34349142EDA9AE900AA7E70 /* NRNovelReadSettingView.swift in Sources */,
|
||||||
@ -1435,10 +1460,12 @@
|
|||||||
F3B859422EE678FB0095A9CC /* NRSettingAPI.swift in Sources */,
|
F3B859422EE678FB0095A9CC /* NRSettingAPI.swift in Sources */,
|
||||||
0373D9522ED58A950017DCC7 /* NRSearchViewModel.swift in Sources */,
|
0373D9522ED58A950017DCC7 /* NRSearchViewModel.swift in Sources */,
|
||||||
F34990BF2EDEDDCF0039E939 /* NRCategoryModel.swift in Sources */,
|
F34990BF2EDEDDCF0039E939 /* NRCategoryModel.swift in Sources */,
|
||||||
|
85CF942F2EEFB2CF006467E3 /* NRLoginView.swift in Sources */,
|
||||||
F34349242EDD3C2400AA7E70 /* NRNovelReadBottomView.swift in Sources */,
|
F34349242EDD3C2400AA7E70 /* NRNovelReadBottomView.swift in Sources */,
|
||||||
039810622ED04F250006E317 /* NRNetwork.swift in Sources */,
|
039810622ED04F250006E317 /* NRNetwork.swift in Sources */,
|
||||||
039810782ED054740006E317 /* NRHud.swift in Sources */,
|
039810782ED054740006E317 /* NRHud.swift in Sources */,
|
||||||
F34991032EE160F00039E939 /* NRUserAPI.swift in Sources */,
|
F34991032EE160F00039E939 /* NRUserAPI.swift in Sources */,
|
||||||
|
85CF94312EEFDA88006467E3 /* NRLoginManager+Apple.swift in Sources */,
|
||||||
85606A9F2EEBE95A005D989D /* NRDashedLineView.swift in Sources */,
|
85606A9F2EEBE95A005D989D /* NRDashedLineView.swift in Sources */,
|
||||||
039810C42ED459440006E317 /* NRHomeNovelHotTagView.swift in Sources */,
|
039810C42ED459440006E317 /* NRHomeNovelHotTagView.swift in Sources */,
|
||||||
F34991122EE170E20039E939 /* NRWebView.swift in Sources */,
|
F34991122EE170E20039E939 /* NRWebView.swift in Sources */,
|
||||||
@ -1546,6 +1573,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = ReaderHive/ReaderHive.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
@ -1555,6 +1583,9 @@
|
|||||||
INFOPLIST_FILE = ReaderHive/Source/Info.plist;
|
INFOPLIST_FILE = ReaderHive/Source/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = ReaderHive;
|
INFOPLIST_KEY_CFBundleDisplayName = ReaderHive;
|
||||||
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType = "";
|
||||||
|
INFOPLIST_KEY_NSCameraUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||||
|
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||||
INFOPLIST_KEY_UIMainStoryboardFile = "";
|
INFOPLIST_KEY_UIMainStoryboardFile = "";
|
||||||
@ -1587,6 +1618,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = ReaderHive/ReaderHive.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
@ -1595,6 +1627,9 @@
|
|||||||
INFOPLIST_FILE = ReaderHive/Source/Info.plist;
|
INFOPLIST_FILE = ReaderHive/Source/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = ReaderHive;
|
INFOPLIST_KEY_CFBundleDisplayName = ReaderHive;
|
||||||
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType = "";
|
||||||
|
INFOPLIST_KEY_NSCameraUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||||
|
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||||
INFOPLIST_KEY_UIMainStoryboardFile = "";
|
INFOPLIST_KEY_UIMainStoryboardFile = "";
|
||||||
@ -1764,6 +1799,25 @@
|
|||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
|
/* Begin XCRemoteSwiftPackageReference section */
|
||||||
|
85CF94352EEFE27E006467E3 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/facebook/facebook-ios-sdk";
|
||||||
|
requirement = {
|
||||||
|
kind = upToNextMajorVersion;
|
||||||
|
minimumVersion = 14.1.0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
||||||
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
|
85CF94362EEFE27E006467E3 /* FacebookLogin */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 85CF94352EEFE27E006467E3 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */;
|
||||||
|
productName = FacebookLogin;
|
||||||
|
};
|
||||||
|
/* End XCSwiftPackageProductDependency section */
|
||||||
};
|
};
|
||||||
rootObject = 03980F5D2ED009E30006E317 /* Project object */;
|
rootObject = 03980F5D2ED009E30006E317 /* Project object */;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import Alamofire
|
import Alamofire
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
struct NRUserAPI {
|
struct NRUserAPI {
|
||||||
|
|
||||||
@ -26,4 +27,35 @@ struct NRUserAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static func requestSignThirdLogin(model: NRThirdSignModel, completer: ((_ token: NRLoginToken?) -> Void)?) {
|
||||||
|
|
||||||
|
var param = NRNetwork.Parameters(path: "/customer/login")
|
||||||
|
param.method = .post
|
||||||
|
param.parameters = model.toDictionary()
|
||||||
|
|
||||||
|
NRNetwork.request(parameters: param) { (response: NRNetwork.Response<NRLoginToken>) in
|
||||||
|
if response.isSuccess {
|
||||||
|
completer?(response.data)
|
||||||
|
} else {
|
||||||
|
completer?(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestLogout(completer: ((_ token: NRLoginToken?) -> Void)?) {
|
||||||
|
var param = NRNetwork.Parameters(path: "/customer/signout")
|
||||||
|
param.method = .post
|
||||||
|
param.isLoding = true
|
||||||
|
|
||||||
|
NRNetwork.request(parameters: param) { (response: NRNetwork.Response<NRLoginToken>) in
|
||||||
|
if response.isSuccess {
|
||||||
|
completer?(response.data)
|
||||||
|
} else {
|
||||||
|
completer?(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
internal import WebKit
|
internal import WebKit
|
||||||
|
import ZLPhotoBrowser
|
||||||
|
|
||||||
///APP交互
|
///APP交互
|
||||||
let kNRWebMessageAPP = "js2app"
|
let kNRWebMessageAPP = "js2app"
|
||||||
@ -23,6 +24,76 @@ let kNRWebMessageAccountDeletionFinish = "accountLogout"
|
|||||||
extension NRWebViewController {
|
extension NRWebViewController {
|
||||||
|
|
||||||
func nr_webViewUserContentController(didReceive message: WKScriptMessage) {
|
func nr_webViewUserContentController(didReceive message: WKScriptMessage) {
|
||||||
|
let name = message.name
|
||||||
|
let body = message.body
|
||||||
|
|
||||||
|
switch name {
|
||||||
|
case kNRWebMessageOpenFeedbackList:
|
||||||
|
let vc = NRAppWebViewController()
|
||||||
|
vc.webUrl = kNRFeedBackListWebUrl
|
||||||
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
|
||||||
|
case kNRWebMessageOpenFeedbackDetail:
|
||||||
|
guard let body = body as? [String : Any] else { return }
|
||||||
|
guard let id = body["id"] as? Int else { return }
|
||||||
|
|
||||||
|
let vc = NRAppWebViewController()
|
||||||
|
vc.id = "\(id)"
|
||||||
|
vc.webUrl = kNRFeedBackDetailWebUrl
|
||||||
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
|
||||||
|
case kNRWebMessageOpenPhotoPicker:
|
||||||
|
openPhotoPicker()
|
||||||
|
|
||||||
|
// case kNRWebMessageAPP:
|
||||||
|
// guard let body = message.body as? [String : Any] else { return }
|
||||||
|
// guard let model = FAWebMessageModel.deserialize(from: body) else { return }
|
||||||
|
// let type = model.type
|
||||||
|
// let data = model.data
|
||||||
|
//
|
||||||
|
// if type == "login" {
|
||||||
|
//// let view = FALoginView()
|
||||||
|
//// view.present(in: nil)
|
||||||
|
//
|
||||||
|
// } else {
|
||||||
|
//
|
||||||
|
// guard let urlStr = data?.link else { return }
|
||||||
|
// guard let url = URL(string: urlStr) else { return }
|
||||||
|
// if UIApplication.shared.canOpenURL(url) {
|
||||||
|
// UIApplication.shared.open(url)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
case kNRWebMessageAccountDeletionFinish:
|
||||||
|
self.navigationController?.popToRootViewController(animated: true)
|
||||||
|
NotificationCenter.default.post(name: NRLoginManager.loginStateDidChangeNotification, object: nil)
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///打开相册
|
||||||
|
private func openPhotoPicker() {
|
||||||
|
|
||||||
|
ZLPhotoConfiguration.default().allowSelectOriginal = false
|
||||||
|
ZLPhotoConfiguration.default().maxSelectCount = 1
|
||||||
|
ZLPhotoConfiguration.default().allowEditImage = false
|
||||||
|
ZLPhotoConfiguration.default().allowSelectVideo = false
|
||||||
|
ZLPhotoConfiguration.default().allowSelectGif = false
|
||||||
|
ZLPhotoConfiguration.default().allowTakePhotoInLibrary = false
|
||||||
|
|
||||||
|
let picker = ZLPhotoPicker()
|
||||||
|
picker.selectImageBlock = { [weak self] (results, _) in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let image = results.first?.image else { return }
|
||||||
|
guard let imageData = image.jpegData(compressionQuality: 0.8) else { return }
|
||||||
|
let imageDataStr = imageData.base64EncodedString(options: .endLineWithCarriageReturn)
|
||||||
|
|
||||||
|
let js = "uploadConvertImage('\(imageDataStr)')"
|
||||||
|
self.webView.evaluateJavaScript(js)
|
||||||
|
}
|
||||||
|
|
||||||
|
picker.showPhotoLibrary(sender: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -115,6 +115,7 @@ extension NRHomeNovelNewArrivalsCell {
|
|||||||
|
|
||||||
categoryView.snp.makeConstraints { make in
|
categoryView.snp.makeConstraints { make in
|
||||||
make.left.equalToSuperview()
|
make.left.equalToSuperview()
|
||||||
|
make.right.lessThanOrEqualToSuperview()
|
||||||
make.top.equalTo(titleLabel.snp.bottom).offset(4)
|
make.top.equalTo(titleLabel.snp.bottom).offset(4)
|
||||||
make.height.equalTo(20)
|
make.height.equalTo(20)
|
||||||
}
|
}
|
||||||
|
|||||||
110
ReaderHive/Class/Me/V/NRLoginView.swift
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
//
|
||||||
|
// NRLoginView.swift
|
||||||
|
// ReaderHive
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/15.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import HWPanModal
|
||||||
|
import SnapKit
|
||||||
|
|
||||||
|
class NRLoginView: NRPanModalContentView {
|
||||||
|
|
||||||
|
|
||||||
|
private lazy var bgView = UIImageView(image: UIImage(named: "bg_image_01"))
|
||||||
|
|
||||||
|
private lazy var titleView = UIImageView(image: UIImage(named: "login_logo_icon"))
|
||||||
|
|
||||||
|
private lazy var appleLoginButton: UIButton = {
|
||||||
|
var configuration = UIButton.Configuration.plain()
|
||||||
|
configuration.background.backgroundColor = .F_2_EFEE
|
||||||
|
configuration.background.cornerRadius = 24
|
||||||
|
configuration.image = UIImage(named: "apple_login_logo_icon")
|
||||||
|
configuration.imagePadding = 8
|
||||||
|
configuration.attributedTitle = AttributedString("Login with Apple".localized, attributes: AttributeContainer([
|
||||||
|
.font : UIFont.font(ofSize: 14, weight: .medium),
|
||||||
|
.foregroundColor : UIColor.black
|
||||||
|
]))
|
||||||
|
|
||||||
|
let button = UIButton(configuration: configuration, primaryAction: UIAction(handler: { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.login(type: .apple)
|
||||||
|
}))
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var facebookLoginButton: UIButton = {
|
||||||
|
var configuration = UIButton.Configuration.plain()
|
||||||
|
configuration.background.backgroundColor = .F_2_EFEE
|
||||||
|
configuration.background.cornerRadius = 24
|
||||||
|
configuration.image = UIImage(named: "facebook_login_logo_icon")
|
||||||
|
configuration.imagePadding = 8
|
||||||
|
configuration.attributedTitle = AttributedString("Login with Facebook".localized, attributes: AttributeContainer([
|
||||||
|
.font : UIFont.font(ofSize: 14, weight: .medium),
|
||||||
|
.foregroundColor : UIColor.black
|
||||||
|
]))
|
||||||
|
|
||||||
|
let button = UIButton(configuration: configuration, primaryAction: UIAction(handler: { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.login(type: .faceBook)
|
||||||
|
}))
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
contentHeight = 220 + UIScreen.safeBottom
|
||||||
|
nr_setupUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
private func login(type: NRLoginManager.LoginType) {
|
||||||
|
NRHud.show()
|
||||||
|
NRLoginManager.manager.thirdLogin(type: type, presentingViewController: nil) { [weak self] isFinish in
|
||||||
|
NRHud.dismiss()
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard isFinish else { return }
|
||||||
|
self.dismiss(animated: true) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension NRLoginView {
|
||||||
|
|
||||||
|
private func nr_setupUI() {
|
||||||
|
addSubview(bgView)
|
||||||
|
addSubview(titleView)
|
||||||
|
addSubview(appleLoginButton)
|
||||||
|
addSubview(facebookLoginButton)
|
||||||
|
|
||||||
|
bgView.snp.makeConstraints { make in
|
||||||
|
make.left.right.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
titleView.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(24)
|
||||||
|
}
|
||||||
|
|
||||||
|
appleLoginButton.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(44)
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(84)
|
||||||
|
make.height.equalTo(48)
|
||||||
|
}
|
||||||
|
|
||||||
|
facebookLoginButton.snp.makeConstraints { make in
|
||||||
|
make.left.right.height.equalTo(appleLoginButton)
|
||||||
|
make.top.equalTo(appleLoginButton.snp.bottom).offset(16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import SnapKit
|
import SnapKit
|
||||||
import YYCategories
|
import YYCategories
|
||||||
|
import HWPanModal
|
||||||
|
|
||||||
class NRMeHeaderView: UITableViewHeaderFooterView {
|
class NRMeHeaderView: UITableViewHeaderFooterView {
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ class NRMeHeaderView: UITableViewHeaderFooterView {
|
|||||||
|
|
||||||
coinsView.userInfo = userInfo
|
coinsView.userInfo = userInfo
|
||||||
|
|
||||||
|
loginButton.isHidden = !(userInfo?.is_tourist ?? false)
|
||||||
|
|
||||||
stackView.nr_removeAllArrangedSubview()
|
stackView.nr_removeAllArrangedSubview()
|
||||||
stackView.addArrangedSubview(coinsView)
|
stackView.addArrangedSubview(coinsView)
|
||||||
@ -72,6 +74,16 @@ class NRMeHeaderView: UITableViewHeaderFooterView {
|
|||||||
return button
|
return button
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private lazy var loginButton: UIButton = {
|
||||||
|
let button = UIButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
let view = NRLoginView()
|
||||||
|
view.present(in: nil)
|
||||||
|
}))
|
||||||
|
button.setImage(UIImage(named: "login_button"), for: .normal)
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
private lazy var stackView: UIStackView = {
|
private lazy var stackView: UIStackView = {
|
||||||
let view = UIStackView()
|
let view = UIStackView()
|
||||||
view.axis = .vertical
|
view.axis = .vertical
|
||||||
@ -121,6 +133,7 @@ extension NRMeHeaderView {
|
|||||||
contentView.addSubview(idBgView)
|
contentView.addSubview(idBgView)
|
||||||
idBgView.addSubview(idLabel)
|
idBgView.addSubview(idLabel)
|
||||||
idBgView.addSubview(copyButton)
|
idBgView.addSubview(copyButton)
|
||||||
|
contentView.addSubview(loginButton)
|
||||||
contentView.addSubview(stackView)
|
contentView.addSubview(stackView)
|
||||||
|
|
||||||
avatarImageView.snp.makeConstraints { make in
|
avatarImageView.snp.makeConstraints { make in
|
||||||
@ -152,6 +165,11 @@ extension NRMeHeaderView {
|
|||||||
make.left.equalTo(idLabel.snp.right).offset(8)
|
make.left.equalTo(idLabel.snp.right).offset(8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loginButton.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalTo(avatarImageView)
|
||||||
|
make.right.equalToSuperview().offset(-16)
|
||||||
|
}
|
||||||
|
|
||||||
stackView.snp.makeConstraints { make in
|
stackView.snp.makeConstraints { make in
|
||||||
make.left.right.equalToSuperview()
|
make.left.right.equalToSuperview()
|
||||||
make.top.equalTo(avatarImageView.snp.bottom).offset(16)
|
make.top.equalTo(avatarImageView.snp.bottom).offset(16)
|
||||||
|
|||||||
@ -13,18 +13,14 @@ class NRFeedbackViewController: NRAppWebViewController {
|
|||||||
self.webUrl = kNRFeedBackHomeWebUrl
|
self.webUrl = kNRFeedBackHomeWebUrl
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "feedback_list_icon_01"), style: .plain, target: self, action: #selector(openFeedbackList))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func openFeedbackList() {
|
||||||
/*
|
let vc = NRAppWebViewController()
|
||||||
// MARK: - Navigation
|
vc.webUrl = kNRFeedBackListWebUrl
|
||||||
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
|
||||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
|
||||||
// Get the new view controller using segue.destination.
|
|
||||||
// Pass the selected object to the new view controller.
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import UIKit
|
|||||||
import IQKeyboardManagerSwift
|
import IQKeyboardManagerSwift
|
||||||
import IQKeyboardToolbarManager
|
import IQKeyboardToolbarManager
|
||||||
import MJRefresh
|
import MJRefresh
|
||||||
|
import FacebookCore
|
||||||
|
|
||||||
|
|
||||||
extension AppDelegate {
|
extension AppDelegate {
|
||||||
@ -30,4 +31,9 @@ extension AppDelegate {
|
|||||||
UIDevice.current.isBatteryMonitoringEnabled = true
|
UIDevice.current.isBatteryMonitoringEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func nr_registThirdparty(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
|
||||||
|
ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
33
ReaderHive/Delegate/AppDelegate+Open.swift
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// AppDelegate+Open.swift
|
||||||
|
// ReaderHive
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/15.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import FacebookCore
|
||||||
|
|
||||||
|
extension SceneDelegate {
|
||||||
|
|
||||||
|
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
|
||||||
|
guard let url = URLContexts.first?.url else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var result = false
|
||||||
|
|
||||||
|
result = ApplicationDelegate.shared.application(UIApplication.shared, open: url, sourceApplication: nil, annotation: [UIApplication.OpenURLOptionsKey.annotation])
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
|
||||||
|
guard let webpageURL = userActivity.webpageURL else { return }
|
||||||
|
var result = false
|
||||||
|
|
||||||
|
result = ApplicationDelegate.shared.application(UIApplication.shared, continue: userActivity)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -6,15 +6,16 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import FacebookCore
|
||||||
|
|
||||||
@main
|
@main
|
||||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||||
NRTool.appDelegate = self
|
NRTool.appDelegate = self
|
||||||
NRNetworkReachableManager.manager.startMonitoring()
|
NRNetworkReachableManager.manager.startMonitoring()
|
||||||
|
nr_registThirdparty(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: NRNetworkReachableManager.networkStatusDidChangeNotification, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: NRNetworkReachableManager.networkStatusDidChangeNotification, object: nil)
|
||||||
|
|
||||||
|
|||||||
107
ReaderHive/Libs/Login/NRLoginManager+Apple.swift
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
//
|
||||||
|
// NRLoginManager+Apple.swift
|
||||||
|
// ReaderHive
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/15.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import AuthenticationServices
|
||||||
|
|
||||||
|
extension NRLoginManager {
|
||||||
|
|
||||||
|
private struct AssociatedKeys {
|
||||||
|
static var appleLoginHandle: Int?
|
||||||
|
}
|
||||||
|
|
||||||
|
private var appleLoginHandle: ((_ model: NRThirdSignModel?) -> Void)? {
|
||||||
|
set {
|
||||||
|
objc_setAssociatedObject(self, &AssociatedKeys.appleLoginHandle, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
|
||||||
|
}
|
||||||
|
get {
|
||||||
|
return objc_getAssociatedObject(self, &AssociatedKeys.appleLoginHandle) as? ((_ model: NRThirdSignModel?) -> Void)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func nr_appleLogin(completer: ((_ model: NRThirdSignModel?) -> Void)?) {
|
||||||
|
self.appleLoginHandle = completer
|
||||||
|
|
||||||
|
let appleIDProvider = ASAuthorizationAppleIDProvider()
|
||||||
|
let request = appleIDProvider.createRequest()
|
||||||
|
request.requestedScopes = [.fullName, .email]
|
||||||
|
|
||||||
|
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
|
||||||
|
authorizationController.delegate = self
|
||||||
|
authorizationController.presentationContextProvider = self
|
||||||
|
authorizationController.performRequests()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func jwtDecode(jwtStr: String) -> [String: Any]? {
|
||||||
|
let segments = jwtStr.components(separatedBy: ".")
|
||||||
|
guard segments.count > 1 else { return nil }
|
||||||
|
|
||||||
|
var base64String = segments[1]
|
||||||
|
|
||||||
|
// 处理 Base64 补齐
|
||||||
|
let requiredLength = 4 * Int(ceil(Double(base64String.count) / 4.0))
|
||||||
|
let paddingLength = requiredLength - base64String.count
|
||||||
|
if paddingLength > 0 {
|
||||||
|
base64String += String(repeating: "=", count: paddingLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 替换 URL 安全字符
|
||||||
|
base64String = base64String.replacingOccurrences(of: "-", with: "+")
|
||||||
|
base64String = base64String.replacingOccurrences(of: "_", with: "/")
|
||||||
|
|
||||||
|
// 解码 Base64 数据
|
||||||
|
guard let data = Data(base64Encoded: base64String),
|
||||||
|
let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
|
||||||
|
let payload = jsonObject as? [String: Any] else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: ASAuthorizationControllerDelegate
|
||||||
|
extension NRLoginManager: ASAuthorizationControllerDelegate {
|
||||||
|
|
||||||
|
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
|
||||||
|
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
|
||||||
|
|
||||||
|
let userIdentifier = appleIDCredential.user
|
||||||
|
let fullName = appleIDCredential.fullName
|
||||||
|
|
||||||
|
let identityToken = appleIDCredential.identityToken.flatMap { String(data: $0, encoding: .utf8) }
|
||||||
|
let identityTokenParams = self.jwtDecode(jwtStr: identityToken ?? "")
|
||||||
|
|
||||||
|
var model = NRThirdSignModel()
|
||||||
|
model.platform = .apple
|
||||||
|
model.third_id = userIdentifier
|
||||||
|
model.giving_name = fullName?.givenName
|
||||||
|
model.family_name = fullName?.familyName
|
||||||
|
model.avator = identityTokenParams?["picture"] as? String
|
||||||
|
model.email = identityTokenParams?["email"] as? String
|
||||||
|
|
||||||
|
appleLoginHandle?(model)
|
||||||
|
appleLoginHandle = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
|
||||||
|
appleLoginHandle?(nil)
|
||||||
|
appleLoginHandle = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: ASAuthorizationControllerPresentationContextProviding
|
||||||
|
extension NRLoginManager: ASAuthorizationControllerPresentationContextProviding {
|
||||||
|
|
||||||
|
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
|
||||||
|
return NRTool.keyWindow!
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
59
ReaderHive/Libs/Login/NRLoginManager+Facebook.swift
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
//
|
||||||
|
// NRLoginManager+Facebook.swift
|
||||||
|
// ReaderHive
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/15.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import FacebookLogin
|
||||||
|
|
||||||
|
extension NRLoginManager {
|
||||||
|
|
||||||
|
func nr_facebookLogin(presentingViewController: UIViewController?, completer: ((_ model: NRThirdSignModel?) -> Void)?) {
|
||||||
|
|
||||||
|
let loginManager = LoginManager()
|
||||||
|
loginManager.logOut()
|
||||||
|
loginManager.defaultAudience = .everyone
|
||||||
|
|
||||||
|
loginManager.logIn(permissions: ["public_profile", "email"], from: presentingViewController) { result, error in
|
||||||
|
guard error == nil, let result = result else {
|
||||||
|
completer?(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if result.isCancelled {
|
||||||
|
completer?(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let request = GraphRequest(graphPath: "me", parameters: ["fields" : "id,name,email,picture"], httpMethod: .get)
|
||||||
|
request.start { connection, result, error in
|
||||||
|
guard let result = result as? [String : Any] else {
|
||||||
|
completer?(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var model = NRThirdSignModel()
|
||||||
|
model.platform = .faceBook
|
||||||
|
model.third_id = result["id"] as? String
|
||||||
|
model.email = result["email"] as? String
|
||||||
|
|
||||||
|
if let picture = result["picture"] as? [String : Any],
|
||||||
|
let data = picture["data"] as? [String : Any],
|
||||||
|
let url = data["url"] as? String
|
||||||
|
{
|
||||||
|
model.avator = url
|
||||||
|
}
|
||||||
|
|
||||||
|
if let name = result["name"] as? String {
|
||||||
|
model.family_name = name
|
||||||
|
} else {
|
||||||
|
model.family_name = result["first_name"] as? String
|
||||||
|
model.giving_name = result["last_name"] as? String
|
||||||
|
}
|
||||||
|
completer?(model)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -6,9 +6,17 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
class NRLoginManager: NSObject {
|
class NRLoginManager: NSObject {
|
||||||
|
|
||||||
|
enum LoginType: String, SmartCaseDefaultable {
|
||||||
|
case apple = "Apple"
|
||||||
|
case faceBook = "Facebook"
|
||||||
|
case google = "Google"
|
||||||
|
case tiktok = "Tiktok"
|
||||||
|
}
|
||||||
|
|
||||||
static let manager = NRLoginManager()
|
static let manager = NRLoginManager()
|
||||||
|
|
||||||
private(set) var token = UserDefaults.nr_object(forKey: kNRLoginTokenDefaultsKey, as: NRLoginToken.self)
|
private(set) var token = UserDefaults.nr_object(forKey: kNRLoginTokenDefaultsKey, as: NRLoginToken.self)
|
||||||
@ -30,6 +38,72 @@ class NRLoginManager: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///第三方登录
|
||||||
|
func thirdLogin(type: LoginType, presentingViewController: UIViewController?, completer: ((_ isFinish: Bool) -> Void)?) {
|
||||||
|
switch type {
|
||||||
|
case .apple:
|
||||||
|
nr_appleLogin { [weak self] model in
|
||||||
|
self?.requestSignThirdLogin(thirdSignModel: model, completer: completer)
|
||||||
|
}
|
||||||
|
|
||||||
|
case .faceBook:
|
||||||
|
nr_facebookLogin(presentingViewController: presentingViewController) { [weak self] model in
|
||||||
|
self?.requestSignThirdLogin(thirdSignModel: model, completer: completer)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///后台验证三方登录
|
||||||
|
private func requestSignThirdLogin(thirdSignModel: NRThirdSignModel?, completer: ((_ isFinish: Bool) -> Void)?) {
|
||||||
|
guard let thirdSignModel = thirdSignModel else {
|
||||||
|
completer?(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// FAStatAPI.requestLeaveApp()
|
||||||
|
NRUserAPI.requestSignThirdLogin(model: thirdSignModel) { [weak self] token in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let token = token else {
|
||||||
|
completer?(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.setAccountToken(token)
|
||||||
|
self.userInfo?.is_tourist = false
|
||||||
|
Task {
|
||||||
|
await self.updateUserInfo()
|
||||||
|
}
|
||||||
|
// FAStatAPI.requestEnterApp()
|
||||||
|
// FAStatAPI.requestStatOnLine()
|
||||||
|
completer?(true)
|
||||||
|
NotificationCenter.default.post(name: NRLoginManager.userInfoUpdateNotification, object: nil)
|
||||||
|
NotificationCenter.default.post(name: NRLoginManager.loginStateDidChangeNotification, object: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func logout(completer: ((_ isFinish: Bool) -> Void)?) {
|
||||||
|
// FAStatAPI.requestLeaveApp()
|
||||||
|
|
||||||
|
NRUserAPI.requestLogout { [weak self] token in
|
||||||
|
guard let self = self else { return }
|
||||||
|
if let token = token {
|
||||||
|
self.setAccountToken(token)
|
||||||
|
self.userInfo?.is_tourist = true
|
||||||
|
Task {
|
||||||
|
await self.updateUserInfo()
|
||||||
|
}
|
||||||
|
// FAStatAPI.requestEnterApp()
|
||||||
|
// FAStatAPI.requestStatOnLine()
|
||||||
|
completer?(true)
|
||||||
|
NotificationCenter.default.post(name: NRLoginManager.userInfoUpdateNotification, object: nil)
|
||||||
|
NotificationCenter.default.post(name: NRLoginManager.loginStateDidChangeNotification, object: nil)
|
||||||
|
} else {
|
||||||
|
completer?(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
24
ReaderHive/Libs/Login/NRThirdSignModel.swift
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// NRThirdSignModel.swift
|
||||||
|
// ReaderHive
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/15.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
struct NRThirdSignModel: SmartCodable {
|
||||||
|
|
||||||
|
var third_id: String?
|
||||||
|
var email: String?
|
||||||
|
//姓
|
||||||
|
var family_name: String?
|
||||||
|
//名
|
||||||
|
var giving_name: String?
|
||||||
|
|
||||||
|
var avator: String?
|
||||||
|
|
||||||
|
var platform: NRLoginManager.LoginType?
|
||||||
|
|
||||||
|
}
|
||||||
12
ReaderHive/ReaderHive.entitlements
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-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>com.apple.developer.applesignin</key>
|
||||||
|
<array>
|
||||||
|
<string>Default</string>
|
||||||
|
</array>
|
||||||
|
<key>keychain-access-groups</key>
|
||||||
|
<array/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
BIN
ReaderHive/Source/Assets.xcassets/Image/apple_login_logo_icon.imageset/Apple@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 479 B |
BIN
ReaderHive/Source/Assets.xcassets/Image/apple_login_logo_icon.imageset/Apple@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 674 B |
22
ReaderHive/Source/Assets.xcassets/Image/apple_login_logo_icon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Apple@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Apple@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
22
ReaderHive/Source/Assets.xcassets/Image/facebook_login_logo_icon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Facebook@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Facebook@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
ReaderHive/Source/Assets.xcassets/Image/facebook_login_logo_icon.imageset/Facebook@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 804 B |
BIN
ReaderHive/Source/Assets.xcassets/Image/facebook_login_logo_icon.imageset/Facebook@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
20
ReaderHive/Source/Assets.xcassets/Image/feedback_list_icon_01.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
22
ReaderHive/Source/Assets.xcassets/Image/login_button.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "登录@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "登录@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
ReaderHive/Source/Assets.xcassets/Image/login_button.imageset/登录@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
ReaderHive/Source/Assets.xcassets/Image/login_button.imageset/登录@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
22
ReaderHive/Source/Assets.xcassets/Image/login_logo_icon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "文字LOGO(ReaderHive)@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "文字LOGO(ReaderHive)@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
ReaderHive/Source/Assets.xcassets/Image/login_logo_icon.imageset/文字LOGO(ReaderHive)@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
ReaderHive/Source/Assets.xcassets/Image/login_logo_icon.imageset/文字LOGO(ReaderHive)@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 30 KiB |
@ -2,6 +2,31 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>fb1155849519865831</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>readerhiveapp</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>FacebookAppID</key>
|
||||||
|
<string>1155849519865831</string>
|
||||||
|
<key>FacebookClientToken</key>
|
||||||
|
<string>696d03750f4bc7a888c815b071be555d</string>
|
||||||
|
<key>FacebookDisplayName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
<key>UIApplicationSceneManifest</key>
|
<key>UIApplicationSceneManifest</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>UIApplicationSupportsMultipleScenes</key>
|
<key>UIApplicationSupportsMultipleScenes</key>
|
||||||
|
|||||||
@ -129,6 +129,8 @@
|
|||||||
"Balance" = "Balance";
|
"Balance" = "Balance";
|
||||||
"Daily Coins" = "Daily Coins";
|
"Daily Coins" = "Daily Coins";
|
||||||
"Buy Now" = "Buy Now";
|
"Buy Now" = "Buy Now";
|
||||||
|
"Login with Apple" = "Login with Apple";
|
||||||
|
"Login with Facebook" = "Login with Facebook";
|
||||||
|
|
||||||
"retain_alert_text" = "Unlock every show you love!";
|
"retain_alert_text" = "Unlock every show you love!";
|
||||||
|
|
||||||
|
|||||||