HarmonyOS 6学习:位置权限已开启却仍报错?深度解析与实战解决方案

引言:开发者的困惑时刻

在HarmonyOS应用开发中,位置功能是许多应用的核心能力。然而,不少开发者都遇到过这样一个令人费解的场景:用户明明已经在系统设置中开启了应用的位置权限,但应用运行时仍然提示"未开启位置权限",甚至直接无法获取到任何位置信息。更让人困惑的是,当引导用户跳转到系统设置页查看时,权限开关确实显示为开启状态。

这种"权限已开,功能却失效"的现象,不仅影响用户体验,更让开发者陷入排查困境。本文将深入剖析这一问题的根本原因,并提供一套完整、可直接复用的解决方案,帮助你的应用真正驾驭HarmonyOS的位置能力。

问题根源:权限与服务的双重关卡

要理解这个问题,首先需要明确HarmonyOS中位置访问的双重验证机制

1. 应用权限层(Permission Level)

这是开发者最熟悉的层面。当应用需要访问用户位置时,必须申请并获取相应的位置权限:

  • ohos.permission.LOCATION:精确位置权限

  • ohos.permission.APPROXIMATELY_LOCATION:模糊位置权限

用户可以在系统设置中为每个应用单独授权或拒绝这些权限。但这只是第一道关卡

2. 系统服务层(Service Level)

这是容易被忽略的关键层面。HarmonyOS设备有一个全局位置服务开关,它控制着整个设备的位置服务能力。即使应用获得了位置权限,如果这个全局开关处于关闭状态,所有位置相关功能(包括GNSS、基站、Wi-Fi定位等)都将无法工作。

核心矛盾点

  • 用户可能为了省电或隐私,关闭了设备的全局位置服务

  • 应用只检查了权限状态,没有检查服务状态

  • 系统返回的错误信息可能不够明确,导致开发者误判为权限问题

问题定位:从日志中寻找真相

当遇到位置功能异常时,系统日志是定位问题的关键。以下是两种典型的日志场景:

场景一:权限已正确授予

复制代码
07-22 12:00:48.108 3766-21737 I [IsDynamicRequest:440]Permission: ohos.permission.APPROXIMATELY_LOCATION: state: 0, errorReason: 0
07-22 12:00:48.108 3766-21737 I [IsDynamicRequest:440]Permission: ohos.permission.LOCATION: state: 0, errorReason: 0

state: 0表示权限已被授予。如果看到这样的日志,说明权限层面没有问题。

场景二:位置服务未开启

复制代码
07-22 15:52:56.840 35263-35311 E [(ReportLocationStatus:1217)]ReportLocationStatus line:1217 location switch is off
07-22 15:52:56.861 35263-50703 E [(AddRequestToWorkRecord:508)]AddRequestToWorkRecord line:508 the location switch is off

location switch is off明确指出了问题的根源:设备的全局位置服务开关处于关闭状态。

诊断结论:当应用已获位置权限但无法获取位置时,首先应该检查系统位置服务开关状态,而不是反复请求权限。

完整解决方案:四步实现稳健定位

以下是一个完整的、生产可用的位置服务管理方案,涵盖了权限检查、服务状态验证、用户引导等全流程。

步骤1:声明必要权限

module.json5文件中添加位置权限声明:

复制代码
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.LOCATION",
        "reason": "用于提供精准位置服务",
        "usedScene": {
          "abilities": ["MainAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.APPROXIMATELY_LOCATION",
        "reason": "用于提供模糊位置服务",
        "usedScene": {
          "abilities": ["MainAbility"],
          "when": "always"
        }
      }
    ]
  }
}

步骤2:创建位置服务管理器

封装一个可复用的位置服务管理类:

复制代码
// utils/LocationServiceManager.ets
import { geoLocationManager } from '@kit.LocationKit';
import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { promptAction } from '@kit.ArkUI';

/**
 * 位置服务状态枚举
 */
export enum LocationServiceStatus {
  PERMISSION_GRANTED = 'permission_granted',      // 权限已授予
  PERMISSION_DENIED = 'permission_denied',        // 权限被拒绝
  SERVICE_DISABLED = 'service_disabled',          // 位置服务未开启
  SERVICE_ENABLED = 'service_enabled',            // 位置服务已开启
  ERROR = 'error'                                 // 其他错误
}

/**
 * 位置服务管理器
 * 处理权限申请、服务状态检查、用户引导等全流程
 */
export class LocationServiceManager {
  private context: common.UIAbilityContext;
  private atManager: abilityAccessCtrl.AtManager;

  constructor(context: common.UIAbilityContext) {
    this.context = context;
    this.atManager = abilityAccessCtrl.createAtManager();
  }

  /**
   * 检查并确保位置服务可用
   * @returns 位置服务状态
   */
  async ensureLocationService(): Promise<LocationServiceStatus> {
    try {
      // 1. 检查系统位置服务开关
      const isServiceEnabled = geoLocationManager.isLocationEnabled();
      
      if (!isServiceEnabled) {
        console.warn('系统位置服务未开启');
        return LocationServiceStatus.SERVICE_DISABLED;
      }

      // 2. 检查并申请位置权限
      const permissionStatus = await this.checkAndRequestPermissions();
      
      if (permissionStatus === LocationServiceStatus.PERMISSION_GRANTED) {
        return LocationServiceStatus.SERVICE_ENABLED;
      } else {
        return permissionStatus;
      }

    } catch (error) {
      const err = error as BusinessError;
      console.error(`位置服务检查失败: ${err.code}, ${err.message}`);
      return LocationServiceStatus.ERROR;
    }
  }

  /**
   * 检查并申请位置权限
   */
  private async checkAndRequestPermissions(): Promise<LocationServiceStatus> {
    const permissions: Array<Permissions> = [
      'ohos.permission.LOCATION',
      'ohos.permission.APPROXIMATELY_LOCATION'
    ];

    try {
      // 检查当前权限状态
      const grantStatus = await this.atManager.checkAccessToken(
        this.context.tokenId,
        permissions
      );

      // 如果权限已全部授予,直接返回
      if (grantStatus.every(status => status === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)) {
        return LocationServiceStatus.PERMISSION_GRANTED;
      }

      // 请求权限
      const requestResult = await this.atManager.requestPermissionsFromUser(
        this.context,
        permissions
      );

      const authResults = requestResult.authResults;
      if (authResults.every(result => result === 0)) {
        return LocationServiceStatus.PERMISSION_GRANTED;
      } else {
        console.warn('用户拒绝了位置权限');
        return LocationServiceStatus.PERMISSION_DENIED;
      }

    } catch (error) {
      const err = error as BusinessError;
      console.error(`权限申请失败: ${err.code}, ${err.message}`);
      return LocationServiceStatus.ERROR;
    }
  }

  /**
   * 请求用户开启系统位置服务
   * @returns 是否成功开启
   */
  async requestEnableLocationService(): Promise<boolean> {
    try {
      // 使用系统弹窗请求开启位置服务
      const result = await this.atManager.requestGlobalSwitch(
        this.context,
        abilityAccessCtrl.SwitchType.LOCATION
      );

      console.info(`位置服务请求结果: ${result}`);
      return result;

    } catch (error) {
      const err = error as BusinessError;
      console.error(`请求开启位置服务失败: ${err.code}, ${err.message}`);
      
      // 如果系统弹窗失败,使用自定义引导
      if (err.code === 201) { // 用户取消
        return false;
      }
      
      // 其他错误,引导用户手动开启
      await this.guideToSystemSettings();
      return false;
    }
  }

  /**
   * 引导用户到系统设置手动开启位置服务
   */
  private async guideToSystemSettings(): Promise<void> {
    try {
      const result = await promptAction.showDialog({
        title: '开启位置服务',
        message: '请在系统设置中开启位置服务,以便应用正常使用定位功能。',
        buttons: [
          { text: '前往设置', color: '#007DFF' },
          { text: '取消', color: '#999999' }
        ]
      });

      if (result.index === 0) {
        // 跳转到系统位置服务设置页
        await this.context.startAbility({
          bundleName: 'com.ohos.settings',
          abilityName: 'com.ohos.settings.MainAbility',
          parameters: {
            'settings:uri': 'settings:location'
          }
        });
      }
    } catch (error) {
      console.error('引导用户失败:', error);
    }
  }

  /**
   * 处理权限被拒绝的情况
   */
  async handlePermissionDenied(): Promise<void> {
    try {
      const result = await promptAction.showDialog({
        title: '位置权限被拒绝',
        message: '位置功能需要相关权限才能使用。您可以在系统设置中重新授权。',
        buttons: [
          { text: '前往设置', color: '#007DFF' },
          { text: '取消', color: '#999999' }
        ]
      });

      if (result.index === 0) {
        // 跳转到应用权限设置页
        await this.context.startAbility({
          bundleName: 'com.ohos.settings',
          abilityName: 'com.ohos.settings.MainAbility',
          parameters: {
            'settings:uri': `settings:app:permission:${this.context.bundleName}`
          }
        });
      }
    } catch (error) {
      console.error('处理权限拒绝失败:', error);
    }
  }

  /**
   * 获取当前位置(在确保服务可用后调用)
   */
  async getCurrentLocation(): Promise<geoLocationManager.Location | null> {
    try {
      const status = await this.ensureLocationService();
      
      if (status !== LocationServiceStatus.SERVICE_ENABLED) {
        console.warn(`位置服务不可用: ${status}`);
        return null;
      }

      // 创建定位请求
      const requestInfo: geoLocationManager.LocationRequest = {
        priority: geoLocationManager.LocationRequestPriority.FIRST_FIX, // 首次定位
        scenario: geoLocationManager.LocationScenario.UNSET, // 未设置场景
        maxAccuracy: 100, // 最大精度100米
        timeInterval: 1, // 时间间隔1秒
        distanceInterval: 0, // 距离间隔0米
        maxDeviation: 0 // 最大偏差0米
      };

      // 获取单次定位
      return new Promise((resolve, reject) => {
        geoLocationManager.getCurrentLocation(requestInfo, (err: BusinessError, location: geoLocationManager.Location) => {
          if (err) {
            console.error(`获取位置失败: ${err.code}, ${err.message}`);
            reject(err);
          } else {
            console.info(`获取位置成功: 纬度=${location.latitude}, 经度=${location.longitude}`);
            resolve(location);
          }
        });
      });

    } catch (error) {
      console.error('获取位置过程中出错:', error);
      return null;
    }
  }
}

步骤3:在UI页面中集成

创建一个用户友好的位置功能页面:

复制代码
// view/LocationPage.ets
import { LocationServiceManager, LocationServiceStatus } from '../utils/LocationServiceManager';
import { geoLocationManager } from '@kit.LocationKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct LocationPage {
  private locationManager: LocationServiceManager = new LocationServiceManager(
    this.getUIContext().getHostContext()
  );
  
  @State currentStatus: string = '准备中...';
  @State locationInfo: string = '暂无位置信息';
  @State isRequesting: boolean = false;
  @State showGuide: boolean = false;

  // 初始化检查
  async onPageShow() {
    await this.checkLocationStatus();
  }

  // 检查位置状态
  async checkLocationStatus() {
    this.isRequesting = true;
    this.currentStatus = '检查位置服务状态...';

    const status = await this.locationManager.ensureLocationService();
    
    switch (status) {
      case LocationServiceStatus.SERVICE_ENABLED:
        this.currentStatus = '✅ 位置服务已就绪';
        await this.updateLocation();
        break;
        
      case LocationServiceStatus.SERVICE_DISABLED:
        this.currentStatus = '⚠️ 系统位置服务未开启';
        this.showGuide = true;
        break;
        
      case LocationServiceStatus.PERMISSION_DENIED:
        this.currentStatus = '❌ 位置权限被拒绝';
        this.showGuide = true;
        break;
        
      case LocationServiceStatus.ERROR:
        this.currentStatus = '⚠️ 位置服务检查出错';
        break;
        
      default:
        this.currentStatus = '未知状态';
    }
    
    this.isRequesting = false;
  }

  // 更新位置信息
  async updateLocation() {
    try {
      const location = await this.locationManager.getCurrentLocation();
      
      if (location) {
        this.locationInfo = `纬度: ${location.latitude.toFixed(6)}\n经度: ${location.longitude.toFixed(6)}\n精度: ${location.accuracy}米`;
        
        // 可选:获取地址信息
        await this.getAddressFromCoordinates(location.latitude, location.longitude);
      } else {
        this.locationInfo = '获取位置失败';
      }
    } catch (error) {
      this.locationInfo = '位置获取异常';
      console.error('更新位置失败:', error);
    }
  }

  // 获取地址信息(反向地理编码)
  async getAddressFromCoordinates(latitude: number, longitude: number) {
    try {
      const geoAddress = await geoLocationManager.getAddressFromLocation({
        latitude: latitude,
        longitude: longitude
      });

      if (geoAddress && geoAddress.length > 0) {
        const address = geoAddress[0];
        this.locationInfo += `\n地址: ${address.locale}\n${address.placeName}`;
      }
    } catch (error) {
      // 地址解析失败不影响主要功能
      console.warn('地址解析失败:', error);
    }
  }

  // 处理用户引导
  async handleUserGuide() {
    this.showGuide = false;
    
    const status = await this.locationManager.ensureLocationService();
    
    if (status === LocationServiceStatus.SERVICE_DISABLED) {
      // 请求开启系统位置服务
      const enabled = await this.locationManager.requestEnableLocationService();
      
      if (enabled) {
        await this.checkLocationStatus();
      }
    } else if (status === LocationServiceStatus.PERMISSION_DENIED) {
      // 处理权限拒绝
      await this.locationManager.handlePermissionDenied();
    }
  }

  build() {
    Column({ space: 20 }) {
      // 状态显示
      Text(this.currentStatus)
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .textAlign(TextAlign.Center)
        .width('100%')
        .margin({ top: 40 });

      // 位置信息显示
      Text(this.locationInfo)
        .fontSize(16)
        .textAlign(TextAlign.Start)
        .width('90%')
        .padding(20)
        .backgroundColor('#F5F5F5')
        .borderRadius(10);

      // 操作按钮
      Button('刷新位置')
        .width('80%')
        .height(50)
        .enabled(!this.isRequesting)
        .onClick(async () => {
          await this.checkLocationStatus();
        });

      // 引导提示
      if (this.showGuide) {
        Column({ space: 10 }) {
          Text('需要开启位置服务才能使用此功能')
            .fontSize(14)
            .fontColor('#FF6B35');
          
          Button('立即开启')
            .width('60%')
            .type(ButtonType.Capsule)
            .backgroundColor('#0A59F7')
            .onClick(() => {
              this.handleUserGuide();
            });
        }
        .width('100%')
        .padding(20)
        .backgroundColor('#FFF8E6')
        .borderRadius(10)
        .margin({ top: 20 });
      }

      // 加载指示器
      if (this.isRequesting) {
        LoadingProgress()
          .width(50)
          .height(50)
          .margin({ top: 20 });
      }
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Start);
  }
}

步骤4:高级功能扩展

对于需要持续定位的应用,可以添加位置监听功能:

复制代码
// utils/LocationListener.ets
import { geoLocationManager } from '@kit.LocationKit';
import { BusinessError } from '@kit.BasicServicesKit';

/**
 * 位置监听管理器
 */
export class LocationListenerManager {
  private locationCallback: geoLocationManager.LocationCallback;
  private isListening: boolean = false;
  private requestId: number = 0;

  constructor(
    private onLocationUpdate: (location: geoLocationManager.Location) => void,
    private onError?: (error: BusinessError) => void
  ) {
    this.locationCallback = {
      onLocationReport: (location: geoLocationManager.Location[]) => {
        if (location.length > 0) {
          this.onLocationUpdate(location[0]);
        }
      },
      onErrorReport: (error: BusinessError) => {
        console.error('位置监听出错:', error);
        if (this.onError) {
          this.onError(error);
        }
      }
    };
  }

  /**
   * 开始监听位置变化
   */
  async startListening(): Promise<boolean> {
    if (this.isListening) {
      console.warn('位置监听已启动');
      return true;
    }

    try {
      const requestInfo: geoLocationManager.LocationRequest = {
        priority: geoLocationManager.LocationRequestPriority.ACCURACY,
        scenario: geoLocationManager.LocationScenario.NAVIGATION,
        maxAccuracy: 50,
        timeInterval: 5, // 5秒更新一次
        distanceInterval: 10, // 10米更新一次
        maxDeviation: 1
      };

      this.requestId = geoLocationManager.on('locationChange', requestInfo, this.locationCallback);
      this.isListening = true;
      
      console.info('位置监听已启动,requestId:', this.requestId);
      return true;

    } catch (error) {
      const err = error as BusinessError;
      console.error('启动位置监听失败:', err);
      return false;
    }
  }

  /**
   * 停止监听位置变化
   */
  stopListening(): void {
    if (this.isListening && this.requestId > 0) {
      try {
        geoLocationManager.off('locationChange', this.requestId);
        this.isListening = false;
        console.info('位置监听已停止');
      } catch (error) {
        console.error('停止位置监听失败:', error);
      }
    }
  }

  /**
   * 获取监听状态
   */
  getListeningStatus(): boolean {
    return this.isListening;
  }
}

最佳实践与进阶技巧

1. 用户体验优化策略

渐进式引导:根据用户操作场景提供不同的引导策略

复制代码
// 根据使用场景提供不同的引导文案
const guideMessages = {
  navigation: '开启位置服务,获取精准导航路线',
  weather: '开启位置服务,获取本地天气预报',
  social: '开启位置服务,发现附近的朋友',
  default: '开启位置服务,享受更多功能'
};

function getGuideMessage(scene: string): string {
  return guideMessages[scene] || guideMessages.default;
}

智能重试机制:在用户拒绝后,选择合适的时机再次询问

复制代码
class SmartPermissionRetry {
  private lastRequestTime: number = 0;
  private retryCount: number = 0;
  
  async requestWithRetry(
    requestFunc: () => Promise<boolean>,
    maxRetries: number = 3
  ): Promise<boolean> {
    const now = Date.now();
    
    // 检查是否应该重试(至少间隔24小时)
    if (this.retryCount > 0 && now - this.lastRequestTime < 24 * 60 * 60 * 1000) {
      console.info('距离上次请求时间太短,暂不重试');
      return false;
    }
    
    if (this.retryCount >= maxRetries) {
      console.info('已达到最大重试次数');
      return false;
    }
    
    this.lastRequestTime = now;
    this.retryCount++;
    
    return await requestFunc();
  }
  
  resetRetryCount(): void {
    this.retryCount = 0;
    this.lastRequestTime = 0;
  }
}

2. 性能与功耗优化

按需定位:根据应用状态调整定位策略

复制代码
enum LocationStrategy {
  HIGH_ACCURACY = 'high_accuracy',    // 高精度,用于导航
  BALANCED = 'balanced',              // 平衡模式,用于常规定位
  LOW_POWER = 'low_power',            // 低功耗,用于后台更新
  PASSIVE = 'passive'                 // 被动模式,仅在其他应用定位时更新
}

function getLocationRequest(strategy: LocationStrategy): geoLocationManager.LocationRequest {
  const baseRequest: geoLocationManager.LocationRequest = {
    priority: geoLocationManager.LocationRequestPriority.ACCURACY,
    scenario: geoLocationManager.LocationScenario.UNSET,
    maxAccuracy: 100,
    timeInterval: 10,
    distanceInterval: 0,
    maxDeviation: 0
  };

  switch (strategy) {
    case LocationStrategy.HIGH_ACCURACY:
      return {
        ...baseRequest,
        priority: geoLocationManager.LocationRequestPriority.ACCURACY,
        scenario: geoLocationManager.LocationScenario.NAVIGATION,
        maxAccuracy: 10,
        timeInterval: 1
      };
      
    case LocationStrategy.LOW_POWER:
      return {
        ...baseRequest,
        priority: geoLocationManager.LocationRequestPriority.LOW_POWER,
        scenario: geoLocationManager.LocationScenario.TRAJECTORY_TRACKING,
        maxAccuracy: 500,
        timeInterval: 60
      };
      
    default:
      return baseRequest;
  }
}

3. 错误处理与监控

全面的错误分类处理

复制代码
class LocationErrorHandler {
  static handleError(error: BusinessError): void {
    const errorCode = error.code;
    
    switch (errorCode) {
      case 201: // 用户取消
        console.warn('用户取消了位置服务请求');
        break;
        
      case 202: // 权限拒绝
        console.error('位置权限被拒绝');
        this.logPermissionDenial();
        break;
        
      case 203: // 服务不可用
        console.error('位置服务不可用');
        this.checkServiceStatus();
        break;
        
      case 204: // 定位超时
        console.warn('定位请求超时');
        this.suggestRetry();
        break;
        
      case 205: // 网络错误
        console.error('网络连接异常');
        this.checkNetworkStatus();
        break;
        
      default:
        console.error(`未知位置错误: ${errorCode}`, error.message);
        this.reportToAnalytics(error);
    }
  }
  
  private static logPermissionDenial(): void {
    // 记录权限拒绝统计,用于优化引导策略
    const analyticsData = {
      event: 'location_permission_denied',
      timestamp: Date.now(),
      retryCount: this.getRetryCount()
    };
    // 上报分析平台
  }
  
  private static suggestRetry(): void {
    // 在合适时机提示用户重试
    setTimeout(() => {
      promptAction.showToast({
        message: '定位信号较弱,正在重试...',
        duration: 3000
      });
    }, 5000);
  }
}

常见问题排查指南

Q1: 权限已开启,但isLocationEnabled()返回false?

  • 检查设备设置:确认用户是否在系统设置中关闭了位置服务

  • 检查飞行模式:飞行模式会关闭所有无线功能包括位置服务

  • 检查省电模式:某些省电模式会限制位置服务

Q2: 用户开启了位置服务,但定位精度很差?

  • 检查定位模式:确认使用的是GNSS定位还是网络定位

  • 检查环境因素:室内、高楼区域会影响GPS信号

  • 建议用户:移动到开阔区域,或开启Wi-Fi辅助定位

Q3: 后台定位被系统限制?

  • 检查后台权限:HarmonyOS对后台定位有严格限制

  • 使用地理围栏:考虑使用地理围栏替代持续后台定位

  • 申请后台权限:如确实需要,向用户说明原因并申请后台定位权限

Q4: 不同设备定位表现不一致?

  • 设备能力差异:不同设备的GPS芯片、天线设计不同

  • 系统版本差异:不同HarmonyOS版本的位置策略可能有调整

  • 建议方案:实现设备能力检测,根据设备能力调整定位策略

总结

HarmonyOS的位置服务管理是一个需要细致处理的系统工程。通过本文的深入解析和实战方案,你应该掌握:

  1. 理解双重验证:位置权限 ≠ 位置服务,必须同时检查两个层面

  2. 正确流程设计:检查服务状态 → 申请权限 → 获取位置

  3. 优雅用户引导:根据具体场景提供清晰的引导和说明

  4. 全面错误处理:分类处理各种异常情况,提升应用稳定性

核心要点回顾

  • 使用geoLocationManager.isLocationEnabled()检查系统服务开关

  • 使用requestGlobalSwitch()引导用户开启位置服务

  • 实现渐进式引导,避免频繁打扰用户

  • 根据应用场景选择合适的定位策略和精度

记住,优秀的位置服务体验不仅仅是技术实现,更是对用户使用场景的深度理解。当你的应用能够智能地处理各种位置相关场景,在权限、服务、精度、功耗之间找到最佳平衡点时,用户将获得更加流畅和愉悦的使用体验。

通过本文的实践方案,你的HarmonyOS应用将能够提供专业级的位置服务体验,让用户在任何场景下都能可靠地使用位置相关功能。

相关推荐
被温水煮的青蛙2 小时前
ArkUI List 图片拖动排序最佳实践
harmonyos
暖阳之下2 小时前
学习周报四十一
学习
liulian09163 小时前
【Flutter for OpenHarmony第三方库】Flutter for OpenHarmony应用更新检测功能实战指南
flutter·华为·学习方法·harmonyos
IntMainJhy3 小时前
【Flutter for OpenHarmony 】第三方库 实战:`cached_network_image` 图片缓存+骨架屏鸿蒙适配全指南✨
flutter·缓存·harmonyos
青衫码上行3 小时前
【从零开始学习JVM】栈中存的是指针还是对象 + 堆分为哪几部分
java·jvm·学习·面试
轻口味3 小时前
HarmonyOS 6 轻相机应用开发1:功能介绍与框架搭建
数码相机·华为·harmonyos
952363 小时前
SpringMVC
后端·学习·spring
nashane3 小时前
HarmonyOS 6学习:界面布局“消消乐”——实战拆解组件遮挡与快照技术
深度学习·学习·harmonyos·harmony app
_张一凡4 小时前
【大语言模型学习】2026年十大LLM训练数据集汇总
人工智能·学习·语言模型·aigc·大模型训练·llm数据集