Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#import <UIKit/UIKit.h>
#import <OneSignalFramework/OneSignalFramework.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate, OSNotificationPermissionObserver, OSInAppMessageLifecycleListener, OSPushSubscriptionObserver, OSNotificationLifecycleListener, OSInAppMessageClickListener, OSNotificationClickListener, OSUserStateObserver, OSUserJwtInvalidatedListener>
@interface AppDelegate : UIResponder <UIApplicationDelegate, OSNotificationPermissionObserver, OSInAppMessageLifecycleListener, OSPushSubscriptionObserver, OSNotificationLifecycleListener, OSInAppMessageClickListener, OSNotificationClickListener, OSUserStateObserver, OSUserJwtInvalidatedListener, OSLogListener>

@property (strong, nonatomic) UIWindow *window;

Expand Down
6 changes: 6 additions & 0 deletions iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
// [FIRApp configure];

NSLog(@"Bundle URL: %@", [[NSBundle mainBundle] bundleURL]);
// Uncomment to test LogListener
// [OneSignal.Debug addLogListener:self];
[OneSignal.Debug setLogLevel:ONE_S_LL_VERBOSE];
[OneSignal.Debug setAlertLevel:ONE_S_LL_NONE];

Expand Down Expand Up @@ -203,4 +205,8 @@ - (void)application:(UIApplication *)application
completionHandler(UIBackgroundFetchResultNoData);
}

- (void)onLogEvent:(OneSignalLogEvent * _Nonnull)event {
NSLog(@"Dev App onLogEvent: %@", event.entry);
}

@end
8 changes: 7 additions & 1 deletion iOS_SDK/OneSignalDevApp/OneSignalDevApp/SwiftTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@
import Foundation
import OneSignalFramework

class SwiftTest: NSObject, OSUserJwtInvalidatedListener {
class SwiftTest: NSObject, OSUserJwtInvalidatedListener, OSLogListener {
func onLogEvent(_ event: OneSignalLogEvent) {
print("Dev App onLogEvent: \(event.level) - \(event.entry)")
}

func onUserJwtInvalidated(event: OSUserJwtInvalidatedEvent) {
print("event: \(event.jsonRepresentation())")
print("externalId: \(event.externalId)")
Expand All @@ -42,5 +46,7 @@ class SwiftTest: NSObject, OSUserJwtInvalidatedListener {
OneSignal.updateUserJwt(externalId: "euid", token: "token")
OneSignal.addUserJwtInvalidatedListener(self)
OneSignal.removeUserJwtInvalidatedListener(self)
OneSignal.Debug.addLogListener(self)
OneSignal.Debug.removeLogListener(self)
}
}
10 changes: 9 additions & 1 deletion iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@
3C47A975292642B100312125 /* OneSignalConfigManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C47A973292642B100312125 /* OneSignalConfigManager.m */; };
3C4F9E4428A4466C009F453A /* OSOperationRepo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C4F9E4328A4466C009F453A /* OSOperationRepo.swift */; };
3C5117172B15C31E00563465 /* OSUserState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5117162B15C31E00563465 /* OSUserState.swift */; };
3C5501402E09CF0100E77DF7 /* OSCopyOnWriteSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C55013E2E09CF0100E77DF7 /* OSCopyOnWriteSet.h */; };
3C5501412E09CF0100E77DF7 /* OSCopyOnWriteSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C55013F2E09CF0100E77DF7 /* OSCopyOnWriteSet.m */; };
3C5929E32CAD9EC50020D6FF /* OneSignalUserManagerImpl+OSLoggable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5929E22CAD9EC50020D6FF /* OneSignalUserManagerImpl+OSLoggable.swift */; };
3C5929E52CAE523E0020D6FF /* MockUserJwtInvalidatedListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5929E42CAE523E0020D6FF /* MockUserJwtInvalidatedListener.swift */; };
3C62999F2BEEA34800649187 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3C62999E2BEEA34800649187 /* PrivacyInfo.xcprivacy */; };
Expand Down Expand Up @@ -1279,6 +1281,8 @@
3C47A973292642B100312125 /* OneSignalConfigManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OneSignalConfigManager.m; sourceTree = "<group>"; };
3C4F9E4328A4466C009F453A /* OSOperationRepo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSOperationRepo.swift; sourceTree = "<group>"; };
3C5117162B15C31E00563465 /* OSUserState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSUserState.swift; sourceTree = "<group>"; };
3C55013E2E09CF0100E77DF7 /* OSCopyOnWriteSet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OSCopyOnWriteSet.h; sourceTree = "<group>"; };
3C55013F2E09CF0100E77DF7 /* OSCopyOnWriteSet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OSCopyOnWriteSet.m; sourceTree = "<group>"; };
3C5929E22CAD9EC50020D6FF /* OneSignalUserManagerImpl+OSLoggable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OneSignalUserManagerImpl+OSLoggable.swift"; sourceTree = "<group>"; };
3C5929E42CAE523E0020D6FF /* MockUserJwtInvalidatedListener.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUserJwtInvalidatedListener.swift; sourceTree = "<group>"; };
3C62999E2BEEA34800649187 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2678,9 +2682,9 @@
4529DF0B1FA932AC00CEAB1D /* OneSignalTrackFirebaseAnalytics.m */,
DE7D1831270279D9002D3A5D /* OSNotificationClasses.h */,
DE7D183527027AA0002D3A5D /* OneSignalLog.h */,
DE7D183327027A73002D3A5D /* OneSignalLog.m */,
3CCF44BC299B17290021964D /* OneSignalWrapper.h */,
3CCF44BD299B17290021964D /* OneSignalWrapper.m */,
DE7D183327027A73002D3A5D /* OneSignalLog.m */,
DE7D187627037A16002D3A5D /* OneSignalCoreHelper.h */,
DE7D187827037A26002D3A5D /* OneSignalCoreHelper.m */,
7AE28B8725B8ADF400529100 /* OSMacros.h */,
Expand All @@ -2695,6 +2699,8 @@
DEBAAEB42A436D5D00BF2C1C /* OSStubLocation.m */,
DEBA2A272C24D0ED00E234DB /* OSBundleUtils.h */,
DEBA2A252C20E9AA00E234DB /* OSBundleUtils.m */,
3C55013E2E09CF0100E77DF7 /* OSCopyOnWriteSet.h */,
3C55013F2E09CF0100E77DF7 /* OSCopyOnWriteSet.m */,
);
path = Source;
sourceTree = "<group>";
Expand Down Expand Up @@ -3220,6 +3226,7 @@
DE7D182A270271A9002D3A5D /* OneSignalCommonDefines.h in Headers */,
3CE8CC522911AE90000DB0D3 /* OSNetworkingUtils.h in Headers */,
DEBAAEB02A435B4D00BF2C1C /* OSLocation.h in Headers */,
3C5501402E09CF0100E77DF7 /* OSCopyOnWriteSet.h in Headers */,
DE971754274C48CF00FC409E /* OSPrivacyConsentController.h in Headers */,
3CE8CC4E2911ADD1000DB0D3 /* OSDeviceUtils.h in Headers */,
3C47A974292642B100312125 /* OneSignalConfigManager.h in Headers */,
Expand Down Expand Up @@ -4531,6 +4538,7 @@
DE7D182E270275FA002D3A5D /* OneSignalTrackFirebaseAnalytics.m in Sources */,
DE51DDE5294262AB0073D5C4 /* OSRemoteParamController.m in Sources */,
DE7D182827026F86002D3A5D /* OneSignalUserDefaults.m in Sources */,
3C5501412E09CF0100E77DF7 /* OSCopyOnWriteSet.m in Sources */,
3CC063942B6D6B6B002BB07F /* OneSignalCore.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
43 changes: 43 additions & 0 deletions iOS_SDK/OneSignalSDK/OneSignalCore/Source/OSCopyOnWriteSet.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Modified MIT License
*
* Copyright 2025 OneSignal
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* 1. The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 2. All copies of substantial portions of the Software may only be used in connection
* with services provided by OneSignal.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#import <Foundation/Foundation.h>

/**
Usage of this class should be limited to cases where modification is rare but reads are frequent.
*/
@interface OSCopyOnWriteSet<__covariant ObjectType> : NSObject {
NSMutableSet *_set;
NSLock *_lock;
}

- (instancetype)init;
- (void)addObject:(ObjectType)object;
- (void)removeObject:(ObjectType)object;
- (NSSet *)allObjects;

@end
71 changes: 71 additions & 0 deletions iOS_SDK/OneSignalSDK/OneSignalCore/Source/OSCopyOnWriteSet.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* Modified MIT License
*
* Copyright 2025 OneSignal
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* 1. The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 2. All copies of substantial portions of the Software may only be used in connection
* with services provided by OneSignal.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#import "OSCopyOnWriteSet.h"

@implementation OSCopyOnWriteSet

- (instancetype)init {
if (self = [super init]) {
_set = [[NSMutableSet alloc] init];
_lock = [[NSLock alloc] init];
}
return self;
}

- (void)addObject:(id)object {
[_lock lock];

// Create a new copy and modify it
NSMutableSet *newSet = [_set mutableCopy];
[newSet addObject:object];

// Update the internal set
_set = newSet;

[_lock unlock];
}

- (void)removeObject:(id)object {
[_lock lock];

// Create a new copy and modify it
NSMutableSet *newSet = [_set mutableCopy];
[newSet removeObject:object];

// Update the internal set
_set = newSet;

[_lock unlock];
}

- (NSSet *)allObjects {
// Read operation - no lock needed
return _set;
}

@end
31 changes: 31 additions & 0 deletions iOS_SDK/OneSignalSDK/OneSignalCore/Source/OneSignalLog.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,41 @@ typedef NS_ENUM(NSUInteger, ONE_S_LOG_LEVEL) {
ONE_S_LL_VERBOSE
};

@interface OneSignalLogEvent : NSObject
@property(readonly)ONE_S_LOG_LEVEL level;
@property(readonly, nonnull)NSString *entry;
@end

@protocol OSLogListener <NSObject>
- (void)onLogEvent:(OneSignalLogEvent *_Nonnull)event;
@end

@protocol OSDebug <NSObject>
/**
The log level the OneSignal SDK should be writing to the Xcode log. Defaults to [LogLevel.WARN].

WARNING: This should not be set higher than LogLevel.WARN in a production setting.
*/
+ (void)setLogLevel:(ONE_S_LOG_LEVEL)logLevel;
/**
The log level the OneSignal SDK should be showing as a modal. Defaults to [LogLevel.NONE].

WARNING: This should not be used in a production setting.
*/
+ (void)setAlertLevel:(ONE_S_LOG_LEVEL)logLevel NS_REFINED_FOR_SWIFT;
+ (void)_dump;
/**
Add a listener to receive all logging messages the SDK produces.
Useful to capture and send logs to your server.

NOTE: All log messages are always passed, LogLevel has no effect on this.
*/
+ (void)addLogListener:(NSObject<OSLogListener>*_Nonnull)listener NS_REFINED_FOR_SWIFT;
/**
Removes a listener added by addLogListener
*/
+ (void)removeLogListener:(NSObject<OSLogListener>*_Nonnull)listener NS_REFINED_FOR_SWIFT;

@end

@interface OneSignalLog : NSObject <OSDebug>
Expand Down
33 changes: 33 additions & 0 deletions iOS_SDK/OneSignalSDK/OneSignalCore/Source/OneSignalLog.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@
#import <Foundation/Foundation.h>
#import "OneSignalLog.h"
#import "OSDialogInstanceManager.h"
#import "OSCopyOnWriteSet.h"

@implementation OneSignalLogEvent
- (instancetype)initWithLevel:(ONE_S_LOG_LEVEL)level entry:(NSString*)entry {
_level = level;
_entry = entry;
return self;
}
@end

/**
Implements the Log Level methods of protocol `OSDebug`.
Expand All @@ -42,6 +51,15 @@ @implementation OneSignalLog
return self;
}

+ (OSCopyOnWriteSet<NSObject<OSLogListener> *>*)logListeners {
static OSCopyOnWriteSet<NSObject<OSLogListener> *> *_logListeners;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_logListeners = [OSCopyOnWriteSet new];
});
return _logListeners;
}

+ (void)setLogLevel:(ONE_S_LOG_LEVEL)nsLogLevel {
_nsLogLevel = nsLogLevel;
}
Expand All @@ -50,6 +68,14 @@ + (void)setAlertLevel:(ONE_S_LOG_LEVEL)logLevel {
_alertLogLevel = logLevel;
}

+ (void)addLogListener:(NSObject<OSLogListener>*_Nonnull)listener {
[self.logListeners addObject:listener];
}

+ (void)removeLogListener:(NSObject<OSLogListener>*_Nonnull)listener {
[self.logListeners removeObject:listener];
}

+ (void)_dump {}

+ (void)onesignalLog:(ONE_S_LOG_LEVEL)logLevel message:(NSString* _Nonnull)message {
Expand Down Expand Up @@ -92,6 +118,13 @@ void onesignal_Log(ONE_S_LOG_LEVEL logLevel, NSString* message) {
if (logLevel <= _alertLogLevel) {
[[OSDialogInstanceManager sharedInstance] presentDialogWithTitle:levelString withMessage:message withActions:nil cancelTitle:NSLocalizedString(@"Close", @"Close button") withActionCompletion:nil];
}

for (NSObject<OSLogListener> *listener in OneSignalLog.logListeners.allObjects) {
if ([listener respondsToSelector:@selector(onLogEvent:)]) {
OneSignalLogEvent *event = [[OneSignalLogEvent alloc] initWithLevel:logLevel entry:[levelString stringByAppendingString:message]];
[listener onLogEvent:event];
}
}
}

@end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,14 @@ public class MockUserRequests: NSObject {
]
}

public static func testUnauthorizedailureError() -> NSError {
public static func testUnauthorizedailureError() -> OneSignalClientError {
let userInfo = ["returned": [
"errors": [["title": "token has invalid claims: token is expired", "code": "auth-0"]],
"httpStatusCode": 401
]]
return NSError(domain: "not-important", code: 401, userInfo: userInfo)
let nsError = NSError(domain: "not-important", code: 401, userInfo: userInfo)
let error = OneSignalClientError(code: 401, message: "not-important", responseHeaders: nil, response: nil, underlyingError: nsError)
return error!
}
}

Expand Down
20 changes: 20 additions & 0 deletions iOS_SDK/OneSignalSDK/Source/OneSignalSwiftInterface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,29 @@ public extension OneSignal {
}

public extension OSDebug {
/**
The log level the OneSignal SDK should be showing as a modal. Defaults to [LogLevel.NONE].

WARNING: This should not be used in a production setting.
*/
static func setAlertLevel(_ logLevel: ONE_S_LOG_LEVEL) {
__setAlert(logLevel)
}
/**
Add a listener to receive all logging messages the SDK produces.
Useful to capture and send logs to your server.

NOTE: All log messages are always passed, LogLevel has no effect on this.
*/
static func addLogListener(_ listener: OSLogListener) {
__add(listener)
}
/**
Removes a listener added by addLogListener
*/
static func removeLogListener(_ listener: OSLogListener) {
__remove(listener)
}
}

public extension OSInAppMessages {
Expand Down
Loading