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

如何使用JavaScript获取OneSignal的User ID实现定向推送

问题根因

subscriptionChange事件不触发、getUserId返回NULL是两个原因导致的:

  • 你写的第二段代码在调用init后立刻执行getUserId,此时SDK还没完成和OneSignal服务端的通信、也没走完用户订阅流程,自然拿不到有效值
  • WebView默认会禁用通知权限,部分场景下还会阻断Service Worker注册,而OneSignal必须拿到通知权限、完成Service Worker注册后才会生成有效的userId
分步解决方法

第一步:修正前端SDK初始化逻辑

不要在init后立刻调用getUserId,要等SDK完全就绪、用户完成订阅授权后再取值,可直接使用下面改好的代码:

<script src="https://cdn.onesignal.com/sdks/OneSignalSDK.js" async=""></script>
<script>
window.OneSignal = window.OneSignal || [];
OneSignal.push(function() {
  OneSignal.init({
    appId: "替换成你自己的appId",
    // WebView/本地调试必须加,允许非HTTPS环境下初始化
    allowLocalhostAsSecureOrigin: true,
    // 自动触发通知授权请求
    autoRegister: true,
    // 对应你放在站点根目录的Service Worker文件
    serviceWorkerPath: 'OneSignalSDKWorker.js'
  });

  // 监听SDK初始化完成事件,比subscriptionChange触发时机更稳定
  OneSignal.on('init', function() {
    OneSignal.isPushNotificationsEnabled(function(isEnabled) {
      if (isEnabled) {
        // 已授权直接取userId
        OneSignal.getUserId(function(userId) {
          console.log("OneSignal UserID:", userId);
          document.querySelector(".some").innerHTML = userId;
          // 此处把userId上报到你的后端,和当前登录用户做绑定
        });
      } else {
        // 未授权时主动触发授权弹窗
        OneSignal.registerForPushNotifications();
      }
    });
  });

  // 订阅状态变化时同步更新userId
  OneSignal.on('subscriptionChange', function (isSubscribed) {
    if (isSubscribed) {
      OneSignal.getUserId(function(userId) {
        console.log("订阅状态更新,UserID:", userId);
        document.querySelector(".some").innerHTML = userId;
        // 此处把最新的userId上报到后端更新绑定关系
      });
    }
  });
});
</script>

第二步:给WebView开对应权限

如果是Android端WebView,必须在原生代码里加以下配置,否则通知权限会被系统直接拦截:

// 开启DOM存储
webView.getSettings().setDomStorageEnabled(true);
// 开启JS执行权限
webView.getSettings().setJavaScriptEnabled(true);
// 允许本地文件域跨域访问
webView.getSettings().setAllowFileAccessFromFileURLs(true);
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
// 处理网页端的权限请求,自动放行通知权限
webView.setWebChromeClient(new WebChromeClient() {
  @Override
  public void onPermissionRequest(final PermissionRequest request) {
    request.grant(request.getResources());
  }
});

如果是iOS端WKWebView,需要在配置中打开javaScriptEnabled开关,同时确保App本身已经拿到系统通知权限。

第三步:修改后端推送代码实现定向推送

拿到userId后,把原来全量推送的included_segments字段替换为include_player_ids,传入目标用户的userId即可,改好的PHP代码片段如下:

notify("Alert","Testing Notification");
$content = array("en" => "Testing Notification ");
// $targetUserId 替换为你前端上报的、对应要触达用户的OneSignal userId
$targetUserId = "替换为目标用户的userId";
$fields = array(
    'app_id' => "替换为你的appId",
    // 移除全量推送配置,改为指定用户ID推送
    'include_player_ids' => array($targetUserId),
    'contents' => $content,
    'data' => array("en" => "bar"),
    'large_icon' =>"ic_launcher_round.png",
);

$fields = json_encode($fields);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://onesignal.com/api/v1/notifications");
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json; charset=utf-8',
    'Authorization: Basic 替换为你的REST API Key'
));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

$response = curl_exec($ch);
curl_close($ch);
避坑提醒
  • 必须把OneSignal官方提供的OneSignalSDKWorker.js和OneSignalSDKUpdaterWorker.js两个文件放到站点根目录,否则Service Worker注册失败,永远拿不到userId
  • 单次调用include_player_ids最多支持传2000个userId,批量触达更多用户时需要分批次请求
  • WebView开启无痕模式时Service Worker和本地存储会被禁用,该场景下无法获取有效userId
  • 不要在init调用后立刻执行getUserId,必须等init回调或者subscriptionChange事件触发后再调用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 08:03:19