APNs 消息推送

This commit is contained in:
huangshijie 2024-06-07 16:04:27 +08:00
parent 435904ba62
commit ea0e93be12
8 changed files with 107 additions and 776 deletions

View File

@ -40,6 +40,7 @@
DE9C3A322C0E390200951DEE /* copinismApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9C3A122C0E390200951DEE /* copinismApp.swift */; }; DE9C3A322C0E390200951DEE /* copinismApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9C3A122C0E390200951DEE /* copinismApp.swift */; };
DE9C3A332C0E390200951DEE /* TestSwiftUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9C3A132C0E390200951DEE /* TestSwiftUIView.swift */; }; DE9C3A332C0E390200951DEE /* TestSwiftUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9C3A132C0E390200951DEE /* TestSwiftUIView.swift */; };
DE9C3A362C10AA8000951DEE /* MessageBack.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9C3A352C10AA8000951DEE /* MessageBack.swift */; }; DE9C3A362C10AA8000951DEE /* MessageBack.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9C3A352C10AA8000951DEE /* MessageBack.swift */; };
DE9C3A382C12F2DE00951DEE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9C3A372C12F2DE00951DEE /* AppDelegate.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@ -80,6 +81,7 @@
DE9C3A132C0E390200951DEE /* TestSwiftUIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSwiftUIView.swift; sourceTree = "<group>"; }; DE9C3A132C0E390200951DEE /* TestSwiftUIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSwiftUIView.swift; sourceTree = "<group>"; };
DE9C3A342C0E420400951DEE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; }; DE9C3A342C0E420400951DEE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
DE9C3A352C10AA8000951DEE /* MessageBack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageBack.swift; sourceTree = "<group>"; }; DE9C3A352C10AA8000951DEE /* MessageBack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageBack.swift; sourceTree = "<group>"; };
DE9C3A372C12F2DE00951DEE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -276,6 +278,7 @@
DE9C3A112C0E390200951DEE /* ContentView.swift */, DE9C3A112C0E390200951DEE /* ContentView.swift */,
DE9C3A122C0E390200951DEE /* copinismApp.swift */, DE9C3A122C0E390200951DEE /* copinismApp.swift */,
DE9C3A132C0E390200951DEE /* TestSwiftUIView.swift */, DE9C3A132C0E390200951DEE /* TestSwiftUIView.swift */,
DE9C3A372C12F2DE00951DEE /* AppDelegate.swift */,
); );
path = copinism; path = copinism;
sourceTree = "<group>"; sourceTree = "<group>";
@ -425,6 +428,7 @@
DE9C3A2C2C0E390200951DEE /* TargetItamSwift.swift in Sources */, DE9C3A2C2C0E390200951DEE /* TargetItamSwift.swift in Sources */,
DE9C3A362C10AA8000951DEE /* MessageBack.swift in Sources */, DE9C3A362C10AA8000951DEE /* MessageBack.swift in Sources */,
DE9C3A282C0E390200951DEE /* MessageView.swift in Sources */, DE9C3A282C0E390200951DEE /* MessageView.swift in Sources */,
DE9C3A382C12F2DE00951DEE /* AppDelegate.swift in Sources */,
DE9C3A1F2C0E390200951DEE /* ArticleCardView.swift in Sources */, DE9C3A1F2C0E390200951DEE /* ArticleCardView.swift in Sources */,
DE9C3A182C0E390200951DEE /* TabbarView.swift in Sources */, DE9C3A182C0E390200951DEE /* TabbarView.swift in Sources */,
DE9C3A332C0E390200951DEE /* TestSwiftUIView.swift in Sources */, DE9C3A332C0E390200951DEE /* TestSwiftUIView.swift in Sources */,

View File

@ -4,755 +4,6 @@
<FileRef <FileRef
location = "group:copinism.xcodeproj"> location = "group:copinism.xcodeproj">
</FileRef> </FileRef>
<Group
location = "group:"
name = "">
<Group
location = "group:copinism"
name = "copinism">
<FileRef
location = "group:TestSwiftUIView.swift">
</FileRef>
<Group
location = "group:Assets.xcassets"
name = "Assets.xcassets">
<Group
location = "group:AppIcon.appiconset"
name = "AppIcon.appiconset">
<FileRef
location = "group:2x 1.png">
</FileRef>
<FileRef
location = "group:2x 3.png">
</FileRef>
<FileRef
location = "group:2x 2.png">
</FileRef>
<FileRef
location = "group:icons8-&#x65e5;&#x5e38;&#x8fd0;&#x52a8;-136.png">
</FileRef>
<FileRef
location = "group:icons8-&#x65e5;&#x5e38;&#x8fd0;&#x52a8;-1024.png">
</FileRef>
<FileRef
location = "group:2x 5.png">
</FileRef>
<FileRef
location = "group:2x 4.png">
</FileRef>
<FileRef
location = "group:2x.png">
</FileRef>
<FileRef
location = "group:icons8-&#x65e5;&#x5e38;&#x8fd0;&#x52a8;-76.png">
</FileRef>
<FileRef
location = "group:icons8-&#x65e5;&#x5e38;&#x8fd0;&#x52a8;-192.png">
</FileRef>
<FileRef
location = "group:3x.png">
</FileRef>
<FileRef
location = "group:3x 2.png">
</FileRef>
<FileRef
location = "group:3x 3.png">
</FileRef>
<FileRef
location = "group:3x 1.png">
</FileRef>
<FileRef
location = "group:Contents.json">
</FileRef>
<FileRef
location = "group:icons8-&#x65e5;&#x5e38;&#x8fd0;&#x52a8;-114.png">
</FileRef>
<FileRef
location = "group:icons8-&#x65e5;&#x5e38;&#x8fd0;&#x52a8;-128.png">
</FileRef>
</Group>
<Group
location = "group:AccentColor.colorset"
name = "AccentColor.colorset">
<FileRef
location = "group:Contents.json">
</FileRef>
</Group>
<FileRef
location = "group:Contents.json">
</FileRef>
</Group>
<Group
location = "group:utils"
name = "utils">
<FileRef
location = "group:Http.swift">
</FileRef>
</Group>
<FileRef
location = "group:copinismApp.swift">
</FileRef>
<Group
location = "group:Preview Content"
name = "Preview Content">
<Group
location = "group:Preview Assets.xcassets"
name = "Preview Assets.xcassets">
<FileRef
location = "group:Contents.json">
</FileRef>
</Group>
</Group>
<Group
location = "group:Styles"
name = "Styles">
<FileRef
location = "group:ImageStyle.swift">
</FileRef>
<FileRef
location = "group:TextStyle.swift">
</FileRef>
</Group>
<Group
location = "group:Components"
name = "Components">
<FileRef
location = "group:TabbarView.swift">
</FileRef>
</Group>
<Group
location = "group:api"
name = "api">
<FileRef
location = "group:Target.swift">
</FileRef>
<FileRef
location = "group:Req.swift">
</FileRef>
<FileRef
location = "group:Api.swift">
</FileRef>
</Group>
<Group
location = "group:Data"
name = "Data">
<FileRef
location = "group:CardData.swift">
</FileRef>
</Group>
<Group
location = "group:Views"
name = "Views">
<Group
location = "group:Home"
name = "Home">
<FileRef
location = "group:HomeView.swift">
</FileRef>
<Group
location = "group:Components"
name = "Components">
<FileRef
location = "group:FindView.swift">
</FileRef>
<FileRef
location = "group:CardView.swift">
</FileRef>
<FileRef
location = "group:VicinityView.swift">
</FileRef>
<FileRef
location = "group:FollowView.swift">
</FileRef>
<FileRef
location = "group:ArticleCardView.swift">
</FileRef>
<FileRef
location = "group:NavBarPopupView.swift">
</FileRef>
<FileRef
location = "group:NavBarView.swift">
</FileRef>
</Group>
</Group>
<Group
location = "group:Shopping"
name = "Shopping">
<FileRef
location = "group:ShoppingView.swift">
</FileRef>
</Group>
<Group
location = "group:TabbarLayout"
name = "TabbarLayout">
<FileRef
location = "group:TabbarLayoutView.swift">
</FileRef>
</Group>
<Group
location = "group:Record"
name = "Record">
<FileRef
location = "group:RecordView.swift">
</FileRef>
</Group>
<Group
location = "group:ArticleDetail"
name = "ArticleDetail">
<FileRef
location = "group:ArticleDetailView.swift">
</FileRef>
</Group>
<Group
location = "group:Message"
name = "Message">
<FileRef
location = "group:MessageDetail.swift">
</FileRef>
<FileRef
location = "group:MessageView.swift">
</FileRef>
</Group>
<Group
location = "group:Mine"
name = "Mine">
<FileRef
location = "group:MytargetStatus.swift">
</FileRef>
<FileRef
location = "group:TargetItamSwift.swift">
</FileRef>
<FileRef
location = "group:MineView.swift">
</FileRef>
<FileRef
location = "group:Login.swift">
</FileRef>
</Group>
</Group>
<FileRef
location = "group:ContentView.swift">
</FileRef>
</Group>
<Group
location = "group:Pods"
name = "Pods">
<FileRef
location = "group:Pods.xcodeproj">
</FileRef>
<Group
location = "group:Alamofire"
name = "Alamofire">
<FileRef
location = "group:LICENSE">
</FileRef>
<Group
location = "group:Source"
name = "Source">
<Group
location = "group:Core"
name = "Core">
<FileRef
location = "group:ParameterEncoder.swift">
</FileRef>
<FileRef
location = "group:Session.swift">
</FileRef>
<FileRef
location = "group:Protected.swift">
</FileRef>
<FileRef
location = "group:ParameterEncoding.swift">
</FileRef>
<FileRef
location = "group:AFError.swift">
</FileRef>
<FileRef
location = "group:DataStreamRequest.swift">
</FileRef>
<FileRef
location = "group:DownloadRequest.swift">
</FileRef>
<FileRef
location = "group:WebSocketRequest.swift">
</FileRef>
<FileRef
location = "group:HTTPMethod.swift">
</FileRef>
<FileRef
location = "group:URLConvertible+URLRequestConvertible.swift">
</FileRef>
<FileRef
location = "group:RequestTaskMap.swift">
</FileRef>
<FileRef
location = "group:Notifications.swift">
</FileRef>
<FileRef
location = "group:Response.swift">
</FileRef>
<FileRef
location = "group:Request.swift">
</FileRef>
<FileRef
location = "group:HTTPHeaders.swift">
</FileRef>
<FileRef
location = "group:DataRequest.swift">
</FileRef>
<FileRef
location = "group:UploadRequest.swift">
</FileRef>
<FileRef
location = "group:SessionDelegate.swift">
</FileRef>
</Group>
<Group
location = "group:Features"
name = "Features">
<FileRef
location = "group:MultipartFormData.swift">
</FileRef>
<FileRef
location = "group:RequestInterceptor.swift">
</FileRef>
<FileRef
location = "group:NetworkReachabilityManager.swift">
</FileRef>
<FileRef
location = "group:Concurrency.swift">
</FileRef>
<FileRef
location = "group:CachedResponseHandler.swift">
</FileRef>
<FileRef
location = "group:RetryPolicy.swift">
</FileRef>
<FileRef
location = "group:ServerTrustEvaluation.swift">
</FileRef>
<FileRef
location = "group:RedirectHandler.swift">
</FileRef>
<FileRef
location = "group:URLEncodedFormEncoder.swift">
</FileRef>
<FileRef
location = "group:AlamofireExtended.swift">
</FileRef>
<FileRef
location = "group:MultipartUpload.swift">
</FileRef>
<FileRef
location = "group:Validation.swift">
</FileRef>
<FileRef
location = "group:AuthenticationInterceptor.swift">
</FileRef>
<FileRef
location = "group:EventMonitor.swift">
</FileRef>
<FileRef
location = "group:Combine.swift">
</FileRef>
<FileRef
location = "group:RequestCompression.swift">
</FileRef>
<FileRef
location = "group:ResponseSerialization.swift">
</FileRef>
</Group>
<Group
location = "group:Extensions"
name = "Extensions">
<FileRef
location = "group:URLSessionConfiguration+Alamofire.swift">
</FileRef>
<FileRef
location = "group:OperationQueue+Alamofire.swift">
</FileRef>
<FileRef
location = "group:StringEncoding+Alamofire.swift">
</FileRef>
<FileRef
location = "group:DispatchQueue+Alamofire.swift">
</FileRef>
<FileRef
location = "group:URLRequest+Alamofire.swift">
</FileRef>
<FileRef
location = "group:Result+Alamofire.swift">
</FileRef>
</Group>
<FileRef
location = "group:Alamofire.swift">
</FileRef>
<FileRef
location = "group:PrivacyInfo.xcprivacy">
</FileRef>
</Group>
<FileRef
location = "group:README.md">
</FileRef>
</Group>
<Group
location = "group:Target Support Files"
name = "Target Support Files">
<Group
location = "group:Alamofire"
name = "Alamofire">
<FileRef
location = "group:Alamofire.release.xcconfig">
</FileRef>
<FileRef
location = "group:Alamofire-dummy.m">
</FileRef>
<FileRef
location = "group:Alamofire.debug.xcconfig">
</FileRef>
<FileRef
location = "group:Alamofire-umbrella.h">
</FileRef>
<FileRef
location = "group:Alamofire.modulemap">
</FileRef>
<FileRef
location = "group:ResourceBundle-Alamofire-Alamofire-Info.plist">
</FileRef>
<FileRef
location = "group:Alamofire-prefix.pch">
</FileRef>
</Group>
<Group
location = "group:Pods-copinism"
name = "Pods-copinism">
<FileRef
location = "group:Pods-copinism-resources-Debug-input-files.xcfilelist">
</FileRef>
<FileRef
location = "group:Pods-copinism.release.xcconfig">
</FileRef>
<FileRef
location = "group:Pods-copinism.debug.xcconfig">
</FileRef>
<FileRef
location = "group:Pods-copinism-resources-Release-output-files.xcfilelist">
</FileRef>
<FileRef
location = "group:Pods-copinism-dummy.m">
</FileRef>
<FileRef
location = "group:Pods-copinism-resources-Debug-output-files.xcfilelist">
</FileRef>
<FileRef
location = "group:Pods-copinism-acknowledgements.plist">
</FileRef>
<FileRef
location = "group:Pods-copinism-resources-Release-input-files.xcfilelist">
</FileRef>
<FileRef
location = "group:Pods-copinism-acknowledgements.markdown">
</FileRef>
<FileRef
location = "group:Pods-copinism-umbrella.h">
</FileRef>
<FileRef
location = "group:Pods-copinism.modulemap">
</FileRef>
<FileRef
location = "group:Pods-copinism-resources.sh">
</FileRef>
</Group>
<Group
location = "group:Kingfisher"
name = "Kingfisher">
<FileRef
location = "group:Kingfisher.modulemap">
</FileRef>
<FileRef
location = "group:Kingfisher-umbrella.h">
</FileRef>
<FileRef
location = "group:Kingfisher.release.xcconfig">
</FileRef>
<FileRef
location = "group:Kingfisher-prefix.pch">
</FileRef>
<FileRef
location = "group:Kingfisher-dummy.m">
</FileRef>
<FileRef
location = "group:Kingfisher.debug.xcconfig">
</FileRef>
</Group>
</Group>
<FileRef
location = "group:Manifest.lock">
</FileRef>
<Group
location = "group:Local Podspecs"
name = "Local Podspecs">
</Group>
<Group
location = "group:Headers"
name = "Headers">
<Group
location = "group:Public"
name = "Public">
<Group
location = "group:Alamofire"
name = "Alamofire">
<FileRef
location = "group:Alamofire-umbrella.h">
</FileRef>
<FileRef
location = "group:Alamofire.modulemap">
</FileRef>
</Group>
<Group
location = "group:Kingfisher"
name = "Kingfisher">
<FileRef
location = "group:Kingfisher.modulemap">
</FileRef>
<FileRef
location = "group:Kingfisher-umbrella.h">
</FileRef>
</Group>
</Group>
</Group>
<Group
location = "group:Kingfisher"
name = "Kingfisher">
<FileRef
location = "group:LICENSE">
</FileRef>
<FileRef
location = "group:README.md">
</FileRef>
<Group
location = "group:Sources"
name = "Sources">
<Group
location = "group:Cache"
name = "Cache">
<FileRef
location = "group:Storage.swift">
</FileRef>
<FileRef
location = "group:ImageCache.swift">
</FileRef>
<FileRef
location = "group:MemoryStorage.swift">
</FileRef>
<FileRef
location = "group:DiskStorage.swift">
</FileRef>
<FileRef
location = "group:CacheSerializer.swift">
</FileRef>
<FileRef
location = "group:FormatIndicatedCacheSerializer.swift">
</FileRef>
</Group>
<Group
location = "group:General"
name = "General">
<FileRef
location = "group:Kingfisher.swift">
</FileRef>
<FileRef
location = "group:KingfisherError.swift">
</FileRef>
<FileRef
location = "group:KF.swift">
</FileRef>
<Group
location = "group:ImageSource"
name = "ImageSource">
<FileRef
location = "group:Source.swift">
</FileRef>
<FileRef
location = "group:Resource.swift">
</FileRef>
<FileRef
location = "group:ImageDataProvider.swift">
</FileRef>
<FileRef
location = "group:AVAssetImageDataProvider.swift">
</FileRef>
</Group>
<FileRef
location = "group:KFOptionsSetter.swift">
</FileRef>
<FileRef
location = "group:KingfisherManager.swift">
</FileRef>
<FileRef
location = "group:KingfisherOptionsInfo.swift">
</FileRef>
</Group>
<Group
location = "group:Networking"
name = "Networking">
<FileRef
location = "group:ImageDownloaderDelegate.swift">
</FileRef>
<FileRef
location = "group:RequestModifier.swift">
</FileRef>
<FileRef
location = "group:ImageDataProcessor.swift">
</FileRef>
<FileRef
location = "group:SessionDataTask.swift">
</FileRef>
<FileRef
location = "group:RedirectHandler.swift">
</FileRef>
<FileRef
location = "group:ImageDownloader.swift">
</FileRef>
<FileRef
location = "group:AuthenticationChallengeResponsable.swift">
</FileRef>
<FileRef
location = "group:ImageModifier.swift">
</FileRef>
<FileRef
location = "group:RetryStrategy.swift">
</FileRef>
<FileRef
location = "group:SessionDelegate.swift">
</FileRef>
<FileRef
location = "group:ImagePrefetcher.swift">
</FileRef>
</Group>
<Group
location = "group:Image"
name = "Image">
<FileRef
location = "group:ImageProgressive.swift">
</FileRef>
<FileRef
location = "group:Image.swift">
</FileRef>
<FileRef
location = "group:ImageFormat.swift">
</FileRef>
<FileRef
location = "group:ImageDrawing.swift">
</FileRef>
<FileRef
location = "group:ImageTransition.swift">
</FileRef>
<FileRef
location = "group:ImageProcessor.swift">
</FileRef>
<FileRef
location = "group:GraphicsContext.swift">
</FileRef>
<FileRef
location = "group:Filter.swift">
</FileRef>
<FileRef
location = "group:Placeholder.swift">
</FileRef>
<FileRef
location = "group:GIFAnimatedImage.swift">
</FileRef>
</Group>
<Group
location = "group:Extensions"
name = "Extensions">
<FileRef
location = "group:TVMonogramView+Kingfisher.swift">
</FileRef>
<FileRef
location = "group:ImageView+Kingfisher.swift">
</FileRef>
<FileRef
location = "group:NSButton+Kingfisher.swift">
</FileRef>
<FileRef
location = "group:UIButton+Kingfisher.swift">
</FileRef>
<FileRef
location = "group:WKInterfaceImage+Kingfisher.swift">
</FileRef>
<FileRef
location = "group:NSTextAttachment+Kingfisher.swift">
</FileRef>
</Group>
<Group
location = "group:Views"
name = "Views">
<FileRef
location = "group:Indicator.swift">
</FileRef>
<FileRef
location = "group:AnimatedImageView.swift">
</FileRef>
</Group>
<Group
location = "group:SwiftUI"
name = "SwiftUI">
<FileRef
location = "group:ImageBinder.swift">
</FileRef>
<FileRef
location = "group:KFImage.swift">
</FileRef>
<FileRef
location = "group:KFImageOptions.swift">
</FileRef>
</Group>
<Group
location = "group:Utility"
name = "Utility">
<FileRef
location = "group:Runtime.swift">
</FileRef>
<FileRef
location = "group:CallbackQueue.swift">
</FileRef>
<FileRef
location = "group:Delegate.swift">
</FileRef>
<FileRef
location = "group:ExtensionHelpers.swift">
</FileRef>
<FileRef
location = "group:Result.swift">
</FileRef>
<FileRef
location = "group:SizeExtensions.swift">
</FileRef>
<FileRef
location = "group:Box.swift">
</FileRef>
<FileRef
location = "group:String+MD5.swift">
</FileRef>
</Group>
</Group>
</Group>
</Group>
<FileRef
location = "group:copinism.xcodeproj">
</FileRef>
<FileRef
location = "group:copinism.xcworkspace">
</FileRef>
<FileRef
location = "group:Podfile">
</FileRef>
<FileRef
location = "group:Podfile.lock">
</FileRef>
</Group>
<FileRef <FileRef
location = "group:Pods/Pods.xcodeproj"> location = "group:Pods/Pods.xcodeproj">
</FileRef> </FileRef>

View File

@ -0,0 +1,67 @@
//
// AppDelegate.swift
// copinism
//
// Created by on 2024/6/7.
//
import UIKit
import UserNotifications
class AppDelegate: UIResponder, UIApplicationDelegate {
//
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
if granted {
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
}
}
return true
}
///
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// deviceToken
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: \(token)")
// deviceToken
sendDeviceTokenToServer(token: token)
}
//
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register: \(error)")
}
private func sendDeviceTokenToServer(token: String) {
// API URL
let url = URL(string: "https://yourserver.com/api/deviceToken")!
//
let parameters: [String: Any] = [
"deviceToken": token,
"deviceType": "iOS"
]
// 使 URLSession
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try? JSONSerialization.data(withJSONObject: parameters)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Error sending device token: \(error)")
return
}
print("Device token sent successfully")
}
task.resume()
}
}

View File

@ -18,5 +18,9 @@
<key>NSLocalNotificationUsageDescription <key>NSLocalNotificationUsageDescription
NSLocalNotificationUsageDescription</key> NSLocalNotificationUsageDescription</key>
<string>需要通知权限以便发送新消息通知</string> <string>需要通知权限以便发送新消息通知</string>
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
</dict> </dict>
</plist> </plist>

View File

@ -1,7 +1,7 @@
import SwiftUI import SwiftUI
import Alamofire import Alamofire
struct Message: Identifiable { struct Message: Identifiable, Codable {
let id: UUID let id: UUID
let text: String let text: String
let sender: String let sender: String
@ -9,7 +9,7 @@ struct Message: Identifiable {
let isSelf: Bool let isSelf: Bool
let avatar: String let avatar: String
let num: Int let num: Int
let image: UIImage? let image: Data?
init(id: UUID = UUID(), text: String = "", sender: String, timestamp: String, isSelf: Bool, avatar: String, num: Int = 0, image: UIImage? = nil) { init(id: UUID = UUID(), text: String = "", sender: String, timestamp: String, isSelf: Bool, avatar: String, num: Int = 0, image: UIImage? = nil) {
self.id = id self.id = id
@ -19,20 +19,18 @@ struct Message: Identifiable {
self.isSelf = isSelf self.isSelf = isSelf
self.avatar = avatar self.avatar = avatar
self.num = num self.num = num
self.image = image self.image = image?.jpegData(compressionQuality: 0.8)
} }
} }
struct MessageDetailView: View { struct MessageDetailView: View {
@State private var messages: [Message] = [ @State private var messages: [Message] = []
Message(text: "来了条消息", sender: "系统消息", timestamp: "4:00 PM", isSelf: false, avatar: "avatar")
]
@State private var replyText = "" @State private var replyText = ""
@State private var selectedImage: UIImage? @State private var selectedImage: UIImage?
@State private var selectedFileURL: URL? @State private var selectedFileURL: URL?
@State private var isImagePickerPresented = false @State private var isImagePickerPresented = false
@State private var isDocumentPickerPresented = false @State private var isDocumentPickerPresented = false
@State private var uploadProgress: Double = 0.0 // @State private var uploadProgress: Double = 0.0
@Environment(\.presentationMode) var presentationMode @Environment(\.presentationMode) var presentationMode
var body: some View { var body: some View {
@ -59,7 +57,7 @@ struct MessageDetailView: View {
.font(.system(size: 18)) .font(.system(size: 18))
.foregroundColor(.black) .foregroundColor(.black)
} }
.opacity(0) // .opacity(0)
} }
.padding(.horizontal, 12) .padding(.horizontal, 12)
.padding(.vertical, 8) .padding(.vertical, 8)
@ -71,7 +69,7 @@ struct MessageDetailView: View {
if !message.isSelf { if !message.isSelf {
Image("avatar") Image("avatar")
.CircleImage(size: 30) .CircleImage(size: 30)
if let image = message.image { if let imageData = message.image, let image = UIImage(data: imageData) {
ZStack { ZStack {
Image(uiImage: image) Image(uiImage: image)
.resizable() .resizable()
@ -94,7 +92,7 @@ struct MessageDetailView: View {
Spacer() Spacer()
} else { } else {
Spacer() Spacer()
if let image = message.image { if let imageData = message.image, let image = UIImage(data: imageData) {
ZStack { ZStack {
Image(uiImage: image) Image(uiImage: image)
.resizable() .resizable()
@ -161,7 +159,6 @@ struct MessageDetailView: View {
.padding(.bottom, 8) .padding(.bottom, 8)
.sheet(isPresented: $isImagePickerPresented) { .sheet(isPresented: $isImagePickerPresented) {
ImagePicker(selectedImage: $selectedImage, onImagePicked: { image in ImagePicker(selectedImage: $selectedImage, onImagePicked: { image in
print(image)
sendImageMessage(image: image) sendImageMessage(image: image)
}) })
} }
@ -170,6 +167,9 @@ struct MessageDetailView: View {
} }
} }
.navigationBarBackButtonHidden(true) .navigationBarBackButtonHidden(true)
.onAppear {
loadMessages()
}
.onTapGesture { .onTapGesture {
hideKeyboard() hideKeyboard()
} }
@ -178,30 +178,19 @@ struct MessageDetailView: View {
private func sendMessage() { private func sendMessage() {
let newMessage = Message(text: replyText, sender: "", timestamp: currentTimestamp(), isSelf: true, avatar: "avatar") let newMessage = Message(text: replyText, sender: "", timestamp: currentTimestamp(), isSelf: true, avatar: "avatar")
messages.append(newMessage) messages.append(newMessage)
// let messageData = ["text": replyText, "sender": "", "timestamp": currentTimestamp(), "isSelf": true, "avatar": "avatar"] saveMessages()
// makeAlamofireRequest(api: "YOUR_API_ENDPOINT_HERE", method: .post, param: messageData) { (result: Result<HTTPBinResponse<Message>, AFError>) in
// switch result {
// case .success(let response):
// print("Message sent successfully: \(response)")
// case .failure(let error):
// print("Error sending message: \(error)")
// }
// }
replyText = "" replyText = ""
} }
private func sendImageMessage(image: UIImage) { private func sendImageMessage(image: UIImage) {
let newMessage = Message(sender: "", timestamp: currentTimestamp(), isSelf: true, avatar: "avatar", image: image) let newMessage = Message(sender: "", timestamp: currentTimestamp(), isSelf: true, avatar: "avatar", image: image)
messages.append(newMessage) messages.append(newMessage)
//saveMessages()
// 0.0
uploadProgress = 0.0 uploadProgress = 0.0
// base64
if let imageData = image.jpegData(compressionQuality: 0.8) { if let imageData = image.jpegData(compressionQuality: 0.8) {
uploadFile(api: apiprefixV1+upload, file: imageData) { progress in uploadFile(api: apiprefixV1+upload, file: imageData) { progress in
//
self.uploadProgress = progress self.uploadProgress = progress
} completion: { (result: Result<HTTPBinResponse<Token>, AFError>) in } completion: { (result: Result<HTTPBinResponse<Token>, AFError>) in
print(result) print(result)
@ -209,6 +198,20 @@ struct MessageDetailView: View {
} }
} }
private func saveMessages() {
if let encodedMessages = try? JSONEncoder().encode(messages) {
UserDefaults.standard.set(encodedMessages, forKey: "messages")
}
}
private func loadMessages() {
UserDefaults.standard.removeObject(forKey: "messages")
if let savedMessagesData = UserDefaults.standard.data(forKey: "messages"),
let decodedMessages = try? JSONDecoder().decode([Message].self, from: savedMessagesData) {
messages = decodedMessages
}
}
private func currentTimestamp() -> String { private func currentTimestamp() -> String {
let formatter = DateFormatter() let formatter = DateFormatter()
@ -326,3 +329,4 @@ struct DocumentPicker: UIViewControllerRepresentable {
MessageDetailView() MessageDetailView()
} }

View File

@ -299,7 +299,6 @@ struct MineView: View {
} }
func getTarget(req: TargetMeReq){ func getTarget(req: TargetMeReq){
print(req)
GetMeTargets(req: req){ (result: Result<HTTPBinResponse<TargetMeData>, AFError>) in GetMeTargets(req: req){ (result: Result<HTTPBinResponse<TargetMeData>, AFError>) in
switch result { switch result {
case .success(let body): case .success(let body):

View File

@ -9,6 +9,7 @@ import SwiftUI
@main @main
struct small_red_bookApp: App { struct small_red_bookApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene { var body: some Scene {
WindowGroup { WindowGroup {
ContentView() ContentView()

View File

@ -43,6 +43,7 @@ func uploadFile<T: Decodable>(api: String,file: Data,progressHandler: @escaping
if loginStatus.login { if loginStatus.login {
headers.add(name: "Authorization", value: loginStatus.token) headers.add(name: "Authorization", value: loginStatus.token)
} }
print(api)
AF.upload(file, to: api,headers: headers) AF.upload(file, to: api,headers: headers)
.uploadProgress { progress in .uploadProgress { progress in
progressHandler(progress.fractionCompleted) progressHandler(progress.fractionCompleted)