Ionic设备功能 #

一、相机功能 #

1.1 安装与配置 #

bash
npm install @capacitor/camera
npx cap sync

iOS配置(Info.plist):

xml
<key>NSCameraUsageDescription</key>
<string>需要访问相机以拍照</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册以选择照片</string>

Android配置(AndroidManifest.xml):

xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

1.2 相机服务 #

typescript
// services/camera.service.ts
import { Injectable } from '@angular/core';
import { 
  Camera, 
  CameraResultType, 
  CameraSource,
  Photo 
} from '@capacitor/camera';

@Injectable({
  providedIn: 'root'
})
export class CameraService {
  
  async takePhoto(): Promise<string | null> {
    try {
      const photo = await Camera.getPicture({
        quality: 90,
        allowEditing: true,
        resultType: CameraResultType.Uri,
        source: CameraSource.Camera,
        saveToGallery: true
      });
      
      return photo.webPath;
    } catch (error) {
      console.error('拍照失败:', error);
      return null;
    }
  }
  
  async pickFromGallery(): Promise<string | null> {
    try {
      const photo = await Camera.getPicture({
        quality: 90,
        allowEditing: true,
        resultType: CameraResultType.Uri,
        source: CameraSource.Photos
      });
      
      return photo.webPath;
    } catch (error) {
      console.error('选择照片失败:', error);
      return null;
    }
  }
  
  async checkPermissions(): Promise<boolean> {
    const permissions = await Camera.checkPermissions();
    return permissions.camera === 'granted' && permissions.photos === 'granted';
  }
  
  async requestPermissions(): Promise<boolean> {
    const permissions = await Camera.requestPermissions();
    return permissions.camera === 'granted';
  }
}

1.3 使用示例 #

typescript
import { Component } from '@angular/core';
import { CameraService } from './camera.service';
import { ActionSheetController } from '@ionic/angular';

@Component({
  selector: 'app-profile',
  templateUrl: 'profile.page.html'
})
export class ProfilePage {
  avatar: string | null = null;
  
  constructor(
    private camera: CameraService,
    private actionSheetCtrl: ActionSheetController
  ) {}
  
  async selectAvatar() {
    const actionSheet = await this.actionSheetCtrl.create({
      header: '选择头像',
      buttons: [
        {
          text: '拍照',
          handler: async () => {
            this.avatar = await this.camera.takePhoto();
          }
        },
        {
          text: '从相册选择',
          handler: async () => {
            this.avatar = await this.camera.pickFromGallery();
          }
        },
        {
          text: '取消',
          role: 'cancel'
        }
      ]
    });
    
    await actionSheet.present();
  }
}

二、地理位置 #

2.1 安装与配置 #

bash
npm install @capacitor/geolocation
npx cap sync

iOS配置(Info.plist):

xml
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要获取您的位置以提供更好的服务</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>需要持续获取您的位置以提供导航服务</string>

Android配置(AndroidManifest.xml):

xml
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

2.2 位置服务 #

typescript
// services/location.service.ts
import { Injectable } from '@angular/core';
import { Geolocation, Position } from '@capacitor/geolocation';
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class LocationService {
  private positionSubject = new BehaviorSubject<Position | null>(null);
  private watchId: string | null = null;
  
  position$ = this.positionSubject.asObservable();
  
  async getCurrentPosition(): Promise<Position | null> {
    try {
      const position = await Geolocation.getCurrentPosition({
        enableHighAccuracy: true,
        timeout: 10000
      });
      
      this.positionSubject.next(position);
      return position;
    } catch (error) {
      console.error('获取位置失败:', error);
      return null;
    }
  }
  
  async startWatching(): Promise<void> {
    this.watchId = await Geolocation.watchPosition({
      enableHighAccuracy: true,
      timeout: 10000
    }, (position, error) => {
      if (error) {
        console.error('位置监听错误:', error);
        return;
      }
      
      this.positionSubject.next(position);
    });
  }
  
  async stopWatching(): Promise<void> {
    if (this.watchId) {
      await Geolocation.clearWatch({ id: this.watchId });
      this.watchId = null;
    }
  }
  
  async checkPermissions(): Promise<boolean> {
    const permissions = await Geolocation.checkPermissions();
    return permissions.location === 'granted';
  }
  
  async requestPermissions(): Promise<boolean> {
    const permissions = await Geolocation.requestPermissions();
    return permissions.location === 'granted';
  }
  
  // 计算两点距离(米)
  calculateDistance(
    lat1: number, lon1: number,
    lat2: number, lon2: number
  ): number {
    const R = 6371e3;
    const φ1 = lat1 * Math.PI / 180;
    const φ2 = lat2 * Math.PI / 180;
    const Δφ = (lat2 - lat1) * Math.PI / 180;
    const Δλ = (lon2 - lon1) * Math.PI / 180;
    
    const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
              Math.cos(φ1) * Math.cos(φ2) *
              Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    
    return R * c;
  }
}

三、推送通知 #

3.1 安装与配置 #

bash
npm install @capacitor/push-notifications
npx cap sync

3.2 推送服务 #

typescript
// services/push.service.ts
import { Injectable } from '@angular/core';
import { PushNotifications, PushNotificationSchema } from '@capacitor/push-notifications';
import { Router } from '@angular/router';

@Injectable({
  providedIn: 'root'
})
export class PushService {
  
  constructor(private router: Router) {}
  
  async init(): Promise<void> {
    // 请求权限
    const result = await PushNotifications.requestPermissions();
    
    if (result.receive === 'granted') {
      // 注册推送
      await PushNotifications.register();
      
      // 监听事件
      this.listenEvents();
    }
  }
  
  private listenEvents(): void {
    // 注册成功
    PushNotifications.addListener('registration', (token) => {
      console.log('推送token:', token.value);
      // 发送token到服务器
    });
    
    // 注册失败
    PushNotifications.addListener('registrationError', (error) => {
      console.error('推送注册失败:', error);
    });
    
    // 收到推送
    PushNotifications.addListener('pushNotificationReceived', (notification) => {
      console.log('收到推送:', notification);
    });
    
    // 点击推送
    PushNotifications.addListener('pushNotificationActionPerformed', (action) => {
      console.log('点击推送:', action);
      
      // 处理跳转
      const data = action.notification.data;
      if (data?.url) {
        this.router.navigate([data.url]);
      }
    });
  }
  
  async getDeliveredNotifications(): Promise<PushNotificationSchema[]> {
    const result = await PushNotifications.getDeliveredNotifications();
    return result.notifications;
  }
  
  async removeAllDeliveredNotifications(): Promise<void> {
    await PushNotifications.removeAllDeliveredNotifications();
  }
}

四、传感器 #

4.1 加速度计 #

bash
npm install @capacitor/motion
npx cap sync
typescript
import { Motion } from '@capacitor/motion';

async watchAcceleration() {
  await Motion.addListener('accel', (event) => {
    console.log('加速度:', event.acceleration);
  });
}

async stopWatching() {
  await Motion.removeAllListeners();
}

4.2 指南针 #

typescript
import { DeviceOrientation } from '@capacitor/device-orientation';

async watchOrientation() {
  await DeviceOrientation.addListener('orientation', (event) => {
    console.log('方向:', event.alpha, event.beta, event.gamma);
  });
}

五、其他设备功能 #

5.1 振动 #

typescript
import { Haptics, ImpactStyle } from '@capacitor/haptics';

// 轻触
async lightImpact() {
  await Haptics.impact({ style: ImpactStyle.Light });
}

// 中等触感
async mediumImpact() {
  await Haptics.impact({ style: ImpactStyle.Medium });
}

// 重触感
async heavyImpact() {
  await Haptics.impact({ style: ImpactStyle.Heavy });
}

// 振动
async vibrate() {
  await Haptics.vibrate();
}

5.2 屏幕方向 #

typescript
import { ScreenOrientation } from '@capacitor/screen-orientation';

// 锁定横屏
async lockLandscape() {
  await ScreenOrientation.lock({ orientation: 'landscape' });
}

// 锁定竖屏
async lockPortrait() {
  await ScreenOrientation.lock({ orientation: 'portrait' });
}

// 解锁
async unlock() {
  await ScreenOrientation.unlock();
}

// 获取当前方向
async getOrientation() {
  const { type } = await ScreenOrientation.orientation();
  return type;
}

5.3 应用信息 #

typescript
import { App } from '@capacitor/app';

// 获取应用信息
async getAppInfo() {
  const info = await App.getInfo();
  console.log('应用信息:', info);
}

// 获取应用状态
App.addListener('appStateChange', (state) => {
  console.log('应用状态:', state.isActive);
});

// 返回按钮处理
App.addListener('backButton', (event) => {
  console.log('返回按钮按下');
});

六、最佳实践 #

6.1 权限检查 #

typescript
async function checkAndRequestPermissions() {
  // 检查权限
  const hasPermission = await checkPermission();
  
  if (!hasPermission) {
    // 请求权限
    const granted = await requestPermission();
    
    if (!granted) {
      // 引导用户到设置页面
      showPermissionAlert();
      return false;
    }
  }
  
  return true;
}

6.2 错误处理 #

typescript
async function useDeviceFeature() {
  try {
    const result = await deviceFeature();
    return result;
  } catch (error) {
    if (error.message.includes('permission')) {
      // 权限错误
      showPermissionAlert();
    } else if (error.message.includes('not available')) {
      // 功能不可用
      showFeatureNotAvailableAlert();
    } else {
      // 其他错误
      showGenericError();
    }
    return null;
  }
}

七、总结 #

7.1 设备功能要点 #

功能 插件 用途
相机 @capacitor/camera 拍照、选择照片
位置 @capacitor/geolocation 获取位置
推送 @capacitor/push-notifications 推送通知
振动 @capacitor/haptics 触感反馈
屏幕 @capacitor/screen-orientation 屏幕方向

7.2 下一步 #

掌握了设备功能后,接下来让我们学习 原生插件,了解如何开发自定义插件!

最后更新:2026-03-28