HarmonyOS开发:用户分析——用户行为分析

举报
Jack20 发表于 2026/06/25 20:48:20 2026/06/25
【摘要】 HarmonyOS开发:用户分析——用户行为分析📌 核心要点:用户行为分析是把"用户到底在干嘛"这件事从混沌变成清晰——构建用户画像、量化活跃度、精准分群,让产品决策从"我觉得"变成"数据说"。 背景与动机你有没有遇到过这种场景:产品经理说"我们的用户都喜欢用搜索功能",运营说"不对,用户都是刷推荐流的",开发说"你们都别吵了,我看代码里搜索的调用量比推荐高"。三个人三种说法,谁对?都不...

HarmonyOS开发:用户分析——用户行为分析

📌 核心要点:用户行为分析是把"用户到底在干嘛"这件事从混沌变成清晰——构建用户画像、量化活跃度、精准分群,让产品决策从"我觉得"变成"数据说"。

背景与动机

你有没有遇到过这种场景:产品经理说"我们的用户都喜欢用搜索功能",运营说"不对,用户都是刷推荐流的",开发说"你们都别吵了,我看代码里搜索的调用量比推荐高"。

三个人三种说法,谁对?都不对。因为"喜欢"是个模糊概念,你得用数据说话——搜索渗透率多少?推荐流点击率多少?用户从搜索进来的转化率比推荐高还是低?

用户行为分析要解决的核心问题:

  • 用户是谁:用户画像,给每个用户打上标签,知道你的用户长什么样
  • 用户活跃吗:DAU、MAU、活跃度分层,别把"装了就忘"的用户也算活跃
  • 用户怎么用:使用路径、功能偏好、停留时长,用户到底在用你的什么
  • 用户怎么分:分群策略,不同用户用不同策略,别一锅炖

鸿蒙应用的用户行为分析有其特殊性——分布式场景下用户可能跨设备使用,同一个用户在手机上浏览、在平板上购买,你得把跨设备的行为串起来。

核心原理

用户行为分析的架构:行为采集 → 行为建模 → 画像构建 → 分群分析 → 策略输出

flowchart TB
    subgraph 采集层
        A[页面浏览事件]
        B[功能点击事件]
        C[业务转化事件]
        D[用户属性数据]
    end
    
    subgraph 建模层
        E[行为序列构建]
        F[会话识别]
        G[跨设备归因]
    end
    
    subgraph 画像层
        H[基础画像<br/>年龄/地区/设备]
        I[行为画像<br/>偏好/频次/深度]
        J[价值画像<br/>付费/活跃/留存]
    end
    
    subgraph 分群层
        K[RFM分群]
        L[生命周期分群]
        M[行为聚类分群]
    end
    
    subgraph 输出层
        N[精准推送]
        O[个性化推荐]
        P[运营策略]
    end
    
    A --> E
    B --> E
    C --> E
    D --> H
    
    E --> F --> G
    G --> H
    G --> I
    G --> J
    
    H --> K
    I --> K
    J --> K
    H --> L
    I --> L
    J --> M
    
    K --> N
    L --> O
    M --> P
    
    classDef collect fill:#E17055,stroke:#D63031,color:#fff
    classDef model fill:#FDCB6E,stroke:#F0B429,color:#333
    classDef profile fill:#74B9FF,stroke:#0984E3,color:#fff
    classDef segment fill:#A29BFE,stroke:#6C5CE7,color:#fff
    classDef output fill:#55EFC4,stroke:#00B894,color:#333
    
    class A,B,C,D collect
    class E,F,G model
    class H,I,J profile
    class K,L,M segment
    class N,O,P output

用户行为分析的核心模型:

模型 说明 核心指标
用户画像 给用户打标签,描述用户特征 标签覆盖率、画像完整度
活跃度分析 衡量用户使用频率和深度 DAU、MAU、DAU/MAU比
参与度分析 衡量用户使用质量和粘性 会话时长、页面深度、功能使用率
用户分群 按特征将用户分组 分群规模、群间差异度
RFM模型 按最近消费、频次、金额分层 R值、F值、M值

代码实战

基础用法:用户画像构建

先给用户打标签,这是所有分析的基础。

// UserProfileManager.ets - 用户画像管理
import { analytics } from '@kit.AnalyticsKit';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

// 用户画像标签定义
export enum UserTag {
  // 基础标签
  USER_ID = 'user_id',
  REGISTER_CHANNEL = 'register_channel',
  USER_TYPE = 'user_type',
  CITY = 'city',
  DEVICE_TYPE = 'device_type',
  
  // 行为标签
  LAST_VISIT_TIME = 'last_visit_time',
  VISIT_COUNT_7D = 'visit_count_7d',
  PREFERRED_CATEGORY = 'preferred_category',
  AVG_SESSION_DURATION = 'avg_session_duration',
  
  // 价值标签
  IS_PAID_USER = 'is_paid_user',
  TOTAL_PAYMENT = 'total_payment',
  VIP_LEVEL = 'vip_level',
  LTV = 'ltv',
}

export class UserProfileManager {
  private static instance: UserProfileManager;
  private profileCache: Map<string, string> = new Map();
  
  static getInstance(): UserProfileManager {
    if (!UserProfileManager.instance) {
      UserProfileManager.instance = new UserProfileManager();
    }
    return UserProfileManager.instance;
  }
  
  // 设置单个标签
  setTag(tag: UserTag, value: string): void {
    try {
      analytics.setUserProfile(tag, value);
      this.profileCache.set(tag, value);
      console.info(`[UserProfile] 标签设置: ${tag} = ${value}`);
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[UserProfile] 设置标签失败: ${err.code}`);
    }
  }
  
  // 批量设置标签
  setTags(tags: Record<string, string>): void {
    Object.entries(tags).forEach(([key, value]) => {
      this.setTag(key as UserTag, value);
    });
  }
  
  // 获取缓存标签
  getTag(tag: UserTag): string | undefined {
    return this.profileCache.get(tag);
  }
  
  // 更新用户访问信息(每次启动调用)
  updateVisitInfo(): void {
    const now = Date.now();
    const lastVisit = this.profileCache.get(UserTag.LAST_VISIT_TIME);
    
    // 更新最后访问时间
    this.setTag(UserTag.LAST_VISIT_TIME, now.toString());
    
    // 计算7天内访问次数
    let visitCount = parseInt(this.profileCache.get(UserTag.VISIT_COUNT_7D) || '0');
    visitCount++;
    this.setTag(UserTag.VISIT_COUNT_7D, visitCount.toString());
  }
  
  // 更新付费信息
  updatePaymentInfo(amount: number): void {
    // 标记为付费用户
    this.setTag(UserTag.IS_PAID_USER, 'true');
    
    // 累计付费金额
    let totalPayment = parseFloat(this.profileCache.get(UserTag.TOTAL_PAYMENT) || '0');
    totalPayment += amount;
    this.setTag(UserTag.TOTAL_PAYMENT, totalPayment.toFixed(2));
    
    // 更新VIP等级
    const vipLevel = this.calculateVipLevel(totalPayment);
    this.setTag(UserTag.VIP_LEVEL, vipLevel.toString());
  }
  
  // 计算VIP等级
  private calculateVipLevel(totalPayment: number): number {
    if (totalPayment >= 1000) return 5;
    if (totalPayment >= 500) return 4;
    if (totalPayment >= 200) return 3;
    if (totalPayment >= 50) return 2;
    if (totalPayment > 0) return 1;
    return 0;
  }
}

进阶用法:活跃度与参与度分析

光有画像不够,你还得知道用户活不活跃、参不参与。

// ActivityAnalyzer.ets - 活跃度分析器
import { analytics } from '@kit.AnalyticsKit';
import { preferences } from '@kit.ArkData';
import { common } from '@kit.AbilityKit';

// 活跃度等级
export enum ActivityLevel {
  HIGH = 'high',       // 高活跃:近7天访问≥5天
  MEDIUM = 'medium',   // 中活跃:近7天访问2-4天
  LOW = 'low',         // 低活跃:近7天访问1天
  SILENT = 'silent',   // 沉默:近7天未访问
}

// 参与度指标
export interface EngagementMetrics {
  sessionCount: number;          // 会话数
  avgSessionDuration: number;    // 平均会话时长(秒)
  pageDepth: number;             // 页面深度
  featureUsageRate: number;      // 核心功能使用率
  interactionCount: number;      // 交互次数
}

export class ActivityAnalyzer {
  private static instance: ActivityAnalyzer;
  private context: common.UIAbilityContext | null = null;
  private pref: preferences.Preferences | null = null;
  
  // 会话追踪
  private sessionStartTime: number = 0;
  private sessionPageCount: number = 0;
  private sessionInteractionCount: number = 0;
  
  static getInstance(): ActivityAnalyzer {
    if (!ActivityAnalyzer.instance) {
      ActivityAnalyzer.instance = new ActivityAnalyzer();
    }
    return ActivityAnalyzer.instance;
  }
  
  // 初始化
  async init(context: common.UIAbilityContext): Promise<void> {
    this.context = context;
    try {
      this.pref = await preferences.getPreferences(context, 'activity_data');
    } catch (error) {
      console.error('[ActivityAnalyzer] 初始化失败');
    }
  }
  
  // 开始新会话
  startSession(): void {
    this.sessionStartTime = Date.now();
    this.sessionPageCount = 0;
    this.sessionInteractionCount = 0;
    
    // 记录今日已访问
    this.recordVisitDay();
    
    console.info('[ActivityAnalyzer] 会话开始');
  }
  
  // 结束会话
  endSession(): void {
    if (this.sessionStartTime === 0) return;
    
    const duration = (Date.now() - this.sessionStartTime) / 1000; // 秒
    const metrics: EngagementMetrics = {
      sessionCount: 1,
      avgSessionDuration: duration,
      pageDepth: this.sessionPageCount,
      featureUsageRate: 0, // 需要结合业务计算
      interactionCount: this.sessionInteractionCount,
    };
    
    // 上报会话数据
    analytics.reportEvent('session_end', {
      'duration': duration,
      'page_depth': this.sessionPageCount,
      'interaction_count': this.sessionInteractionCount,
    });
    
    // 更新用户活跃度标签
    this.updateActivityLevel();
    
    // 重置会话数据
    this.sessionStartTime = 0;
    this.sessionPageCount = 0;
    this.sessionInteractionCount = 0;
  }
  
  // 记录页面浏览
  onPageView(pageName: string): void {
    this.sessionPageCount++;
    analytics.reportEvent('page_view', {
      'page_name': pageName,
      'session_page_index': this.sessionPageCount,
    });
  }
  
  // 记录用户交互
  onInteraction(action: string, target: string): void {
    this.sessionInteractionCount++;
    analytics.reportEvent('user_interaction', {
      'action': action,
      'target': target,
    });
  }
  
  // 记录访问日期
  private async recordVisitDay(): Promise<void> {
    if (!this.pref) return;
    
    const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
    const visitDaysStr = await this.pref.get('visit_days_7d', '[]') as string;
    const visitDays: string[] = JSON.parse(visitDaysStr);
    
    // 去重添加今日
    if (!visitDays.includes(today)) {
      visitDays.push(today);
    }
    
    // 只保留近7天
    const sevenDaysAgo = new Date();
    sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
    const filteredDays = visitDays.filter(d => new Date(d) >= sevenDaysAgo);
    
    await this.pref.put('visit_days_7d', JSON.stringify(filteredDays));
    await this.pref.flush();
  }
  
  // 计算活跃度等级
  async getActivityLevel(): Promise<ActivityLevel> {
    if (!this.pref) return ActivityLevel.SILENT;
    
    const visitDaysStr = await this.pref.get('visit_days_7d', '[]') as string;
    const visitDays: string[] = JSON.parse(visitDaysStr);
    const count = visitDays.length;
    
    if (count >= 5) return ActivityLevel.HIGH;
    if (count >= 2) return ActivityLevel.MEDIUM;
    if (count >= 1) return ActivityLevel.LOW;
    return ActivityLevel.SILENT;
  }
  
  // 更新活跃度标签
  private async updateActivityLevel(): Promise<void> {
    const level = await this.getActivityLevel();
    analytics.setUserProfile('activity_level', level);
  }
}

完整示例:用户分群策略

有了画像和活跃度,就可以做用户分群了。不同用户不同策略,这才叫精细化运营。

// UserSegmentation.ets - 用户分群策略
import { analytics } from '@kit.AnalyticsKit';
import { preferences } from '@kit.ArkData';
import { common } from '@kit.AbilityKit';
import { ActivityLevel, ActivityAnalyzer } from './ActivityAnalyzer';

// 分群类型
export enum SegmentType {
  NEW_USER = 'new_user',             // 新用户:注册7天内
  ACTIVE_USER = 'active_user',       // 活跃用户:高活跃+有付费
  POTENTIAL_USER = 'potential_user',  // 潜力用户:高活跃+未付费
  CHURN_RISK = 'churn_risk',         // 流失风险:中活跃下降趋势
  CHURNED = 'churned',               // 已流失:沉默用户
  WHALE = 'whale',                   // 大R用户:付费金额Top5%
}

// 分群结果
export interface SegmentResult {
  segment: SegmentType;
  confidence: number;       // 置信度 0-1
  traits: string[];         // 特征描述
  strategy: string;         // 推荐策略
}

export class UserSegmentation {
  private static instance: UserSegmentation;
  private pref: preferences.Preferences | null = null;
  private currentSegment: SegmentType | null = null;
  
  static getInstance(): UserSegmentation {
    if (!UserSegmentation.instance) {
      UserSegmentation.instance = new UserSegmentation();
    }
    return UserSegmentation.instance;
  }
  
  async init(context: common.UIAbilityContext): Promise<void> {
    this.pref = await preferences.getPreferences(context, 'segment_data');
  }
  
  // 执行分群——核心方法
  async segmentUser(): Promise<SegmentResult> {
    const activityLevel = await ActivityAnalyzer.getInstance().getActivityLevel();
    const isPaidUser = await this.getIsPaidUser();
    const registerDays = await this.getRegisterDays();
    const totalPayment = await this.getTotalPayment();
    const visitTrend = await this.getVisitTrend();
    
    let result: SegmentResult;
    
    // 分群逻辑——优先级从高到低
    if (registerDays <= 7) {
      // 新用户:注册7天内
      result = {
        segment: SegmentType.NEW_USER,
        confidence: 0.95,
        traits: ['注册时间短', '行为模式未定型', '需要引导'],
        strategy: '新手引导+首单优惠+功能推荐',
      };
    } else if (totalPayment >= 500) {
      // 大R用户:累计付费>=500
      result = {
        segment: SegmentType.WHALE,
        confidence: 0.9,
        traits: ['高付费', '高忠诚度', '追求品质'],
        strategy: '专属客服+优先体验+VIP特权',
      };
    } else if (activityLevel === ActivityLevel.HIGH && isPaidUser) {
      // 活跃付费用户
      result = {
        segment: SegmentType.ACTIVE_USER,
        confidence: 0.85,
        traits: ['高活跃', '已付费', '功能深度使用'],
        strategy: '会员续费+交叉推荐+社区互动',
      };
    } else if (activityLevel === ActivityLevel.HIGH && !isPaidUser) {
      // 活跃未付费——潜力用户
      result = {
        segment: SegmentType.POTENTIAL_USER,
        confidence: 0.8,
        traits: ['高活跃', '未付费', '使用免费功能'],
        strategy: '限时优惠+付费功能试用+价值展示',
      };
    } else if (activityLevel === ActivityLevel.MEDIUM && visitTrend === 'declining') {
      // 中活跃但下降——流失风险
      result = {
        segment: SegmentType.CHURN_RISK,
        confidence: 0.7,
        traits: ['活跃度下降', '使用频率减少', '可能流失'],
        strategy: '召回推送+专属优惠+功能更新通知',
      };
    } else if (activityLevel === ActivityLevel.SILENT || activityLevel === ActivityLevel.LOW) {
      // 已流失
      result = {
        segment: SegmentType.CHURNED,
        confidence: 0.75,
        traits: ['长期未访问', '可能已卸载', '需要强召回'],
        strategy: '短信召回+大额优惠券+新功能亮点推送',
      };
    } else {
      // 默认归为潜力用户
      result = {
        segment: SegmentType.POTENTIAL_USER,
        confidence: 0.5,
        traits: ['中等活跃', '行为待观察'],
        strategy: '持续观察+轻度运营',
      };
    }
    
    // 保存分群结果
    this.currentSegment = result.segment;
    analytics.setUserProfile('user_segment', result.segment);
    analytics.setUserProfile('segment_confidence', result.confidence.toString());
    
    // 上报分群事件
    analytics.reportEvent('user_segmented', {
      'segment': result.segment,
      'confidence': result.confidence,
      'activity_level': activityLevel,
      'is_paid': isPaidUser,
      'register_days': registerDays,
    });
    
    return result;
  }
  
  // 获取当前分群
  getCurrentSegment(): SegmentType | null {
    return this.currentSegment;
  }
  
  // ========== 辅助方法 ==========
  
  private async getIsPaidUser(): Promise<boolean> {
    if (!this.pref) return false;
    return (await this.pref.get('is_paid_user', false)) as boolean;
  }
  
  private async getRegisterDays(): Promise<number> {
    if (!this.pref) return 999;
    const registerTime = (await this.pref.get('register_time', 0)) as number;
    if (registerTime === 0) return 999;
    return Math.floor((Date.now() - registerTime) / (1000 * 60 * 60 * 24));
  }
  
  private async getTotalPayment(): Promise<number> {
    if (!this.pref) return 0;
    return (await this.pref.get('total_payment', 0)) as number;
  }
  
  private async getVisitTrend(): Promise<string> {
    if (!this.pref) return 'stable';
    return (await this.pref.get('visit_trend', 'stable')) as string;
  }
}

分群结果的使用——不同用户展示不同首页:

// HomePage.ets - 根据分群展示不同首页
import { UserSegmentation, SegmentType } from '../manager/UserSegmentation';

@Entry
@Component
struct HomePage {
  @State currentSegment: SegmentType = SegmentType.NEW_USER;
  
  async aboutToAppear() {
    const segmentation = UserSegmentation.getInstance();
    const result = await segmentation.segmentUser();
    this.currentSegment = result.segment;
  }
  
  build() {
    Column() {
      // 根据分群展示不同内容
      if (this.currentSegment === SegmentType.NEW_USER) {
        this.NewUserHome()
      } else if (this.currentSegment === SegmentType.WHALE) {
        this.WhaleUserHome()
      } else if (this.currentSegment === SegmentType.POTENTIAL_USER) {
        this.PotentialUserHome()
      } else {
        this.DefaultHome()
      }
    }
    .width('100%')
    .height('100%')
  }
  
  @Builder NewUserHome() {
    // 新手引导+首单优惠
    Column() {
      Text('👋 欢迎来到鸿蒙商城')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
      Text('新用户专享:首单立减20元')
        .fontSize(16)
        .fontColor('#FF6B6B')
        .margin({ top: 12 })
      // 新手引导步骤
      this.GuideSteps()
    }
  }
  
  @Builder WhaleUserHome() {
    // VIP专属
    Column() {
      Text('👑 尊享会员专区')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
      Text('专属客服 · 优先体验 · 极速发货')
        .fontSize(14)
        .fontColor('#8B5CF6')
        .margin({ top: 8 })
    }
  }
  
  @Builder PotentialUserHome() {
    // 限时优惠引导付费
    Column() {
      Text('🔥 限时特惠')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
      Text('开通会员立享7天免费体验')
        .fontSize(16)
        .fontColor('#F59E0B')
        .margin({ top: 12 })
    }
  }
  
  @Builder DefaultHome() {
    Text('首页内容')
  }
  
  @Builder GuideSteps() {
    // 新手引导步骤组件
    Text('1️⃣ 浏览商品 → 2️⃣ 加入购物车 → 3️⃣ 完成首单')
      .fontSize(14)
      .margin({ top: 16 })
  }
}

踩坑与注意事项

1. 画像标签不是越多越好

有些团队一上来就给用户打100个标签,结果呢?标签之间互相矛盾,分析的时候不知道看哪个。标签要精不要多,核心标签控制在20个以内,每个标签都要有明确的业务含义和使用场景。

2. 活跃度定义要贴合业务

DAU/MAU这个比值,不同类型的应用差异巨大。社交应用可能DAU/MAU > 50%,工具类应用可能只有10%。别拿社交应用的标准去要求工具类应用,那只会让团队做无用功。

3. 分群策略要定期更新

用户是会变的——今天的潜力用户,明天可能就变成活跃用户了。分群策略至少每月更新一次,关键分群(如流失风险)每周更新。

4. 跨设备用户识别

鸿蒙分布式场景下,同一个华为账号可能登录多个设备。你得把跨设备的行为串起来,否则同一个用户在手机上算一个,在平板上又算一个,数据就乱了。

// 跨设备用户识别
import { distributedDeviceManager } from '@kit.DistributedDeviceManager';

// 用华为账号ID作为用户唯一标识
async function getUnifiedUserId(): Promise<string> {
  // 优先使用华为账号ID
  const accountId = await getHuaweiAccountId();
  if (accountId) {
    return `hw_${accountId}`;
  }
  // 降级使用设备ID + 本地生成的UUID
  const deviceId = getDeviceId();
  const localUUID = await getLocalUUID();
  return `local_${deviceId}_${localUUID}`;
}

5. 隐私合规

用户画像涉及大量个人数据,必须遵守隐私法规。采集前告知用户、获取同意,敏感标签要脱敏处理,用户有权删除自己的画像数据。

HarmonyOS 6适配说明

HarmonyOS 6在用户分析方面有几项重要更新:

  1. 跨设备画像同步:通过华为账号体系,用户画像可跨设备自动同步,无需手动处理
  2. 隐私计算增强:新增on-device ML能力,部分画像计算可在本地完成,不上传原始数据
  3. 实时分群:分群计算从离线批处理升级为实时流式计算,用户行为变化后秒级更新分群
  4. 分群API标准化:新增analytics.getSegment()标准接口,统一分群查询方式
// HarmonyOS 6 实时分群查询
async function getUserSegment(): Promise<string> {
  try {
    const segment = await analytics.getSegment();
    console.info(`[Analytics] 当前分群: ${segment}`);
    return segment;
  } catch (error) {
    console.error('[Analytics] 分群查询失败');
    return 'unknown';
  }
}

总结

用户行为分析是产品优化的指南针——没有分析,你不知道用户是谁、在干什么、会不会走。用户画像告诉你"用户长什么样",活跃度分析告诉你"用户活不活跃",分群策略告诉你"不同用户该怎么对待"。

维度 评价
学习难度 ⭐⭐⭐☆☆ SDK简单,分析模型设计有门槛
使用频率 ⭐⭐⭐⭐⭐ 持续使用,每日更新
重要程度 ⭐⭐⭐⭐⭐ 直接影响产品决策和运营效果

核心记住三点:画像要精不要多、活跃度定义要贴合业务、分群要定期更新。别搞了100个标签结果一个都用不上,那不叫用户画像,那叫数据垃圾场。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。