You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Objective-C中向Web localStorage存OneSignal ID报错:webView未声明

解决WebView未声明导致的注入JavaScript失败问题

问题原因

你当前在AppDelegate中尝试直接访问webView,但AppDelegate并不负责管理WebView实例——WebView通常属于视图控制器(比如你的MainViewController)的管辖范围,因此会触发“未声明标识符”的编译错误。另外,OneSignal的Player ID在App启动初期可能还未完全生成,直接在application:didFinishLaunchingWithOptions:中处理也可能拿不到有效ID。

正确实现步骤

1. 在MainViewController中声明并配置WebView

优先使用WKWebView(苹果推荐的现代Web组件),先在MainViewController.h中声明:

#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>

@interface MainViewController : UIViewController <WKNavigationDelegate>

@property (nonatomic, strong) WKWebView *webView;

@end

然后在MainViewController.m中完成初始化、加载网页,并处理Player ID注入逻辑:

#import "MainViewController.h"
#import <OneSignalFramework/OneSignalFramework.h>

@implementation MainViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 初始化WKWebView并添加到视图
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
    self.webView.navigationDelegate = self;
    [self.view addSubview:self.webView];
    
    // 加载目标网页
    NSURL *targetUrl = [NSURL URLWithString:@"你的网页地址"];
    [self.webView loadRequest:[NSURLRequest requestWithURL:targetUrl]];
    
    // 监听OneSignal用户信息变化,确保拿到有效的Player ID
    [OneSignal.User addObserver:self selector:@selector(onPlayerIDUpdated:) name:OneSignalUserDidChangeNotification object:nil];
}

// 接收OneSignal Player ID更新通知
- (void)onPlayerIDUpdated:(NSNotification *)notification {
    NSString *playerID = OneSignal.User.onesignalId;
    if (playerID && self.webView) {
        [self injectPlayerIDToLocalStorage:playerID];
    }
}

// 注入Player ID到WebView的localStorage
- (void)injectPlayerIDToLocalStorage:(NSString *)playerID {
    // 转义Player ID中的特殊字符,避免JS语法错误
    NSString *escapedID = [playerID stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"];
    NSString *jsCode = [NSString stringWithFormat:@"localStorage.setItem('OneSignalPlayerID', '%@');", escapedID];
    
    [self.webView evaluateJavaScript:jsCode completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        if (error) {
            NSLog(@"注入JS失败: %@", error.localizedDescription);
        } else {
            NSLog(@"Player ID已存入WebView localStorage");
        }
    }];
}

// 可选:确保网页加载完成后再注入(双重保障)
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    NSString *playerID = OneSignal.User.onesignalId;
    if (playerID) {
        [self injectPlayerIDToLocalStorage:playerID];
    }
}

// 移除监听,避免内存泄漏
- (void)dealloc {
    [OneSignal.User removeObserver:self name:OneSignalUserDidChangeNotification object:nil];
}

@end

2. 调整AppDelegate中的代码

保留Player ID到NSUserDefaults的存储逻辑,但移除WebView相关操作(WebView属于视图层职责):

#import "AppDelegate.h"
#import "MainViewController.h"
#import <OneSignalFramework/OneSignalFramework.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.viewController = [[MainViewController alloc] init];
    
    // OneSignal调试日志配置
    [OneSignal.Debug setLogLevel:ONE_S_LL_VERBOSE];
    
    // 初始化OneSignal
    [OneSignal initialize:@"OneSignal App ID" withLaunchOptions:launchOptions];
    
    // 请求通知权限(建议改用应用内消息弹窗提示)
    [OneSignal.Notifications requestPermission:^(BOOL accepted) {
        NSLog(@"用户接受通知: %d", accepted);
    } fallbackToSettings:true];
    
    // 监听Player ID变化并存储到NSUserDefaults
    [OneSignal.User addObserver:self selector:@selector(onPlayerIDSaved:) name:OneSignalUserDidChangeNotification object:nil];
    
    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (void)onPlayerIDSaved:(NSNotification *)notification {
    NSString *playerID = OneSignal.User.onesignalId;
    if (playerID) {
        NSLog(@"OneSignal Player ID: %@", playerID);
        [[NSUserDefaults standardUserDefaults] setObject:playerID forKey:@"oneSignalPlayerID"];
        [[NSUserDefaults standardUserDefaults] synchronize];
        NSLog(Player ID已存储到NSUserDefaults: %@", playerID);
    } else {
        NSLog(@"OneSignal Player ID为空或未获取到");
    }
}

@end

关键注意事项

  • 职责分离:WebView属于视图层,必须在视图控制器中管理,符合MVC架构规范。
  • ID获取时机:通过监听OneSignalUserDidChangeNotification能确保拿到最新、有效的Player ID,避免启动初期拿空值。
  • 字符转义:Player ID可能包含单引号等特殊字符,必须转义后再注入,否则会引发JS语法错误。
  • 注入时机:在网页加载完成后(didFinishNavigation)注入JS,确保localStorage已处于可用状态。

内容的提问来源于stack exchange,提问作者Kashan Danish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 10:42:11