🌟 引言:打破應用壁壘的數據流通革命

在鴻蒙全場景生態中,應用不再是孤立的信息孤島。跨應用數據共享作為分佈式體驗的核心支撐,讓應用間能夠安全、高效地協同工作。無論是通訊錄應用向社交應用共享聯繫人,還是辦公應用套件間的文檔協作,DataShare和UDMF為開發者提供了一套完整的標準化解決方案,真正實現了"數據隨人走、服務隨身動"的智慧體驗。

一、DataShare架構解析:生產者-消費者模式的現代化實現

DataShare採用經典的生產者-消費者架構,通過標準化接口和安全管控機制,實現應用間的數據安全流通。

1. 核心架構與數據流

// DataShare整體架構示意圖
class DataShareArchitecture {
  // 數據提供方(生產者)
  dataProvider: DataShareExtensionAbility = {
    onCreate: (want: Want, callback: Function) => void,
    onQuery: (uri: string, predicates: DataSharePredicates, 
              columns: string[], callback: Function) => void,
    onInsert: (uri: string, value: ValuesBucket, callback: Function) => void,
    onUpdate: (uri: string, predicates: DataSharePredicates, 
               value: ValuesBucket, callback: Function) => void,
    onDelete: (uri: string, predicates: DataSharePredicates, callback: Function) => void
  }
  
  // 數據訪問方(消費者)
  dataConsumer: DataShareHelper = {
    createDataShareHelper: (context: Context, uri: string) => Promise<DataShareHelper>,
    query: (predicates: DataSharePredicates, columns: string[]) => Promise<ResultSet>,
    insert: (value: ValuesBucket) => Promise<number>,
    update: (predicates: DataSharePredicates, value: ValuesBucket) => Promise<number>,
    delete: (predicates: DataSharePredicates) => Promise<number>
  }
  
  // 通信層:IPC安全通信
  communicationLayer: IPCBridge = {
    securityCheck: new SecurityValidator(),    // 安全校驗
    dataSerialization: new DataSerializer(),   // 數據序列化
    permissionControl: new PermissionManager()  // 權限控制
  }
}

2. 兩種共享模式對比

DataShare支持兩種不同的數據共享模式,適應不同業務場景:

// 模式對比枚舉
enum DataShareMode {
  // 拉起提供方模式:完整業務處理
  PROVIDER_ACTIVE = 'active',
  // 靜默訪問模式:高性能直接訪問  
  SILENT_ACCESS = 'silent'
}

// 模式選擇策略
class DataShareModeSelector {
  static selectMode(operationType: string, dataSensitivity: string): DataShareMode {
    if (dataSensitivity === 'high' || operationType === 'complex_business') {
      return DataShareMode.PROVIDER_ACTIVE
    } else {
      return DataShareMode.SILENT_ACCESS
    }
  }
}
二、DataShareExtensionAbility:數據提供方的完整實現

作為數據提供方,需要繼承DataShareExtensionAbility並實現核心生命週期方法。

1. 基礎數據提供方實現

import Extension from '@ohos.application.DataShareExtensionAbility'
import dataSharePredicates from '@ohos.data.dataSharePredicates'
import relationalStore from '@ohos.data.relationalStore'
import { BusinessError } from '@ohos.base'

@Entry
@Component
struct DataProviderExample {
  private rdbStore: relationalStore.RdbStore | null = null
  private readonly DB_CONFIG = {
    name: 'SharedData.db',
    securityLevel: relationalStore.SecurityLevel.S2
  }
  
  // 數據庫初始化
  async aboutToAppear() {
    await this.initDatabase()
  }
  
  private async initDatabase(): Promise<void> {
    try {
      this.rdbStore = await relationalStore.getRdbStore(getContext(this), this.DB_CONFIG)
      
      // 創建共享數據表
      const createTableSql = `
        CREATE TABLE IF NOT EXISTS shared_contacts (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          name TEXT NOT NULL,
          phone TEXT,
          email TEXT,
          company TEXT,
          created_time INTEGER DEFAULT (strftime('%s', 'now')),
          updated_time INTEGER DEFAULT (strftime('%s', 'now'))
        )
      `
      await this.rdbStore.executeSql(createTableSql)
    } catch (error) {
      console.error('數據庫初始化失敗', error)
    }
  }
}

2. DataShareExtensionAbility完整實現

// 數據提供方Extension實現
export default class ContactDataShareExtension extends Extension {
  private rdbStore: relationalStore.RdbStore | null = null
  private readonly TABLE_NAME = 'shared_contacts'
  
  // Extension生命週期:創建時初始化
  onCreate(want: Want, callback: Function): void {
    console.info('ContactDataShareExtension onCreate')
    
    // 初始化數據庫連接
    this.initRdbStore().then(() => {
      callback()
    }).catch((error: BusinessError) => {
      console.error('數據庫初始化失敗', error)
      callback(error)
    })
  }
  
  // 查詢數據實現
  onQuery(uri: string, predicates: dataSharePredicates.DataSharePredicates, 
          columns: string[], callback: Function): void {
    console.info(`查詢請求: ${uri}`)
    
    // 權限驗證
    if (!this.validateQueryPermission()) {
      callback(new Error('權限驗證失敗'))
      return
    }
    
    this.rdbStore.query(this.TABLE_NAME, predicates, columns, (err: BusinessError, resultSet: relationalStore.ResultSet) => {
      if (err) {
        console.error(`查詢失敗: ${err.code} - ${err.message}`)
        callback(err)
      } else {
        console.info(`查詢成功,返回${resultSet.rowCount}條數據`)
        callback(undefined, resultSet)
      }
    })
  }
  
  // 插入數據實現
  onInsert(uri: string, value: ValuesBucket, callback: Function): void {
    console.info('插入數據請求')
    
    // 數據驗證
    if (!this.validateContactData(value)) {
      callback(new Error('數據驗證失敗'))
      return
    }
    
    // 添加時間戳
    value.created_time = Math.floor(Date.now() / 1000)
    value.updated_time = value.created_time
    
    this.rdbStore.insert(this.TABLE_NAME, value, (err: BusinessError, rowId: number) => {
      if (err) {
        console.error(`插入失敗: ${err.code} - ${err.message}`)
        callback(err)
      } else {
        console.info(`數據插入成功,ID: ${rowId}`)
        callback(undefined, rowId)
        
        // 通知數據變化
        this.notifyChange(uri)
      }
    })
  }
  
  // 數據驗證
  private validateContactData(value: ValuesBucket): boolean {
    return value && value.name && typeof value.name === 'string' && value.name.length > 0
  }
  
  // 權限驗證
  private validateQueryPermission(): boolean {
    // 實際項目中應檢查調用方權限
    return true
  }
}

3. 配置文件設置

// module.json5中的Extension配置
{
  "extensionAbilities": [
    {
      "name": "ContactDataShareExtension",
      "srcEntry": "./ets/contacts/ContactDataShareExtension.ets",
      "label": "$string:contacts_data_provider",
      "description": "$string:contacts_data_description",
      "type": "dataShare",
      "uri": "datashare://com.example.contacts.provider/contacts",
      "exported": true,
      "permissions": [
        {
          "name": "ohos.permission.READ_CONTACTS",
          "grantMode": "system_grant"
        }
      ],
      "metadata": [
        {
          "name": "ohos.extension.dataShare",
          "resource": "$profile:data_share_config"
        }
      ]
    }
  ]
}
三、DataShareHelper:數據消費方的安全訪問

數據消費方通過DataShareHelper實例訪問提供方數據,無需關心底層存儲細節。

1. DataShareHelper初始化與基礎操作

@Entry
@Component
struct DataConsumerExample {
  private dataShareHelper: dataShare.DataShareHelper | null = null
  private readonly CONTACTS_URI = 'datashare://com.example.contacts.provider/contacts'
  
  async aboutToAppear() {
    await this.initDataShareHelper()
  }
  
  // 初始化DataShareHelper
  async initDataShareHelper(): Promise<void> {
    try {
      this.dataShareHelper = await dataShare.createDataShareHelper(
        getContext(this), 
        this.CONTACTS_URI,
        { isProxy: true }  // 啓用代理模式
      )
      console.info('DataShareHelper初始化成功')
      
      // 註冊數據變化監聽
      this.setupDataChangeListener()
    } catch (error) {
      console.error('DataShareHelper初始化失敗', error)
    }
  }
  
  // 查詢聯繫人數據
  async queryContacts(filter?: string): Promise<Contact[]> {
    if (!this.dataShareHelper) {
      throw new Error('DataShareHelper未初始化')
    }
    
    const predicates = new dataSharePredicates.DataSharePredicates()
    if (filter) {
      predicates.contains('name', filter)
    }
    predicates.orderByAsc('name')
    
    const columns = ['id', 'name', 'phone', 'email', 'company']
    
    try {
      const resultSet = await this.dataShareHelper.query(this.CONTACTS_URI, predicates, columns)
      return this.processResultSet(resultSet)
    } catch (error) {
      console.error('查詢聯繫人失敗', error)
      return []
    }
  }
  
  // 添加新聯繫人
  async addContact(contact: Contact): Promise<boolean> {
    if (!this.dataShareHelper) return false
    
    const values: ValuesBucket = {
      name: contact.name,
      phone: contact.phone,
      email: contact.email,
      company: contact.company
    }
    
    try {
      const rowId = await this.dataShareHelper.insert(this.CONTACTS_URI, values)
      console.info(`聯繫人添加成功,ID: ${rowId}`)
      return true
    } catch (error) {
      console.error('添加聯繫人失敗', error)
      return false
    }
  }
}

2. 高級特性:批量操作與數據同步

@Component
struct AdvancedDataOperations {
  private dataShareHelper: dataShare.DataShareHelper | null = null
  
  // 批量插入操作
  async batchImportContacts(contacts: Contact[]): Promise<BatchResult> {
    const results: BatchResult = {
      success: 0,
      failed: 0,
      errors: []
    }
    
    for (let i = 0; i < contacts.length; i++) {
      try {
        await this.addContact(contacts[i])
        results.success++
      } catch (error) {
        results.failed++
        results.errors.push({
          index: i,
          error: error.message,
          contact: contacts[i]
        })
      }
    }
    
    return results
  }
  
  // 數據變化監聽
  setupDataChangeListener(): void {
    this.dataShareHelper.on('dataChange', this.CONTACTS_URI, (changeInfo: DataChangeInfo) => {
      console.info('檢測到數據變化,更新UI')
      this.refreshContactList()
    })
  }
  
  // 安全的數據訪問控制
  async secureQuery(sensitiveField: string): Promise<any> {
    // 檢查調用方權限
    const hasPermission = await this.validateAccessPermission(sensitiveField)
    if (!hasPermission) {
      throw new Error('權限不足,無法訪問敏感數據')
    }
    
    // 記錄審計日誌
    await this.logDataAccess(sensitiveField)
    
    return await this.queryContacts()
  }
}
四、統一數據管理框架UDMF:標準化數據交換

UDMF為跨應用、跨設備數據交互定義了統一標準,解決了數據格式不一致的痛點。

1. UDMF核心概念與數據標準化

// UDMF標準化數據類型定義
enum UDMFDataType {
  PLAIN_TEXT = 'text/plain',
  RICH_TEXT = 'text/richtext',
  HTML = 'text/html',
  JSON = 'application/json',
  IMAGE = 'image/*',
  VIDEO = 'video/*',
  AUDIO = 'audio/*',
  CONTACT = 'application/vnd.ohos.contact',
  CALENDAR = 'application/vnd.ohos.calendar'
}

// 統一數據記錄結構
interface UnifiedRecord {
  type: UDMFDataType
  details: RecordDetail
  properties?: Record<string, any>
  authorization?: AccessControl
}

// 跨應用數據分享
class UDMFDataShare {
  // 分享數據到UDMF
  async shareToUDMF(data: UnifiedRecord, options: ShareOptions): Promise<string> {
    const udmfClient = await this.getUDMFClient()
    const recordId = await udmfClient.insert(data, options)
    
    // 設置訪問權限
    await this.setAccessPolicy(recordId, options.accessPolicy)
    
    return recordId
  }
  
  // 從UDMF讀取數據
  async readFromUDMF(recordId: string, requester: string): Promise<UnifiedRecord> {
    // 驗證訪問權限
    await this.validateAccess(recordId, requester)
    
    return await this.udmfClient.query(recordId)
  }
}

2. 實戰案例:跨應用文件分享

@Entry
@Component
struct FileSharingExample {
  private readonly UDMF_IMAGE_TYPE = 'image/*'
  
  // 分享圖片到其他應用
  async shareImageToEditor(imageUri: string): Promise<void> {
    const imageRecord: UnifiedRecord = {
      type: this.UDMF_IMAGE_TYPE,
      details: {
        uri: imageUri,
        width: 1920,
        height: 1080,
        size: this.getFileSize(imageUri),
        format: 'image/jpeg'
      },
      properties: {
        creationTime: Date.now(),
        author: this.getCurrentUser(),
        sourceApp: this.getAppBundleName()
      }
    }
    
    const shareOptions: ShareOptions = {
      allowedApps: ['com.example.photoeditor'], // 指定可訪問應用
      validityPeriod: 24 * 60 * 60 * 1000, // 24小時有效
      accessPolicy: {
        read: true,
        write: false,
        share: false
      }
    }
    
    try {
      const recordId = await this.udmf.shareToUDMF(imageRecord, shareOptions)
      await this.launchEditorApp(recordId)
    } catch (error) {
      console.error('圖片分享失敗', error)
    }
  }
  
  // 處理接收到的共享數據
  async handleSharedData(recordId: string): Promise<void> {
    const sharedRecord = await this.udmf.readFromUDMF(recordId, this.getAppBundleName())
    
    switch (sharedRecord.type) {
      case UDMFDataType.PLAIN_TEXT:
        await this.processTextData(sharedRecord)
        break
      case UDMFDataType.IMAGE:
        await this.processImageData(sharedRecord)
        break
      case UDMFDataType.CONTACT:
        await this.processContactData(sharedRecord)
        break
      default:
        console.warn('不支持的數據類型:', sharedRecord.type)
    }
    
    // 清理臨時數據
    await this.udmf.delete(recordId)
  }
}
五、安全與權限管理:數據共享的守護者

安全是跨應用數據共享的生命線,鴻蒙提供了多層次的安全保護機制。

1. 權限聲明與驗證

// 權限配置管理
class PermissionManager {
  private readonly REQUIRED_PERMISSIONS = {
    READ_CONTACTS: 'ohos.permission.READ_CONTACTS',
    WRITE_CONTACTS: 'ohos.permission.WRITE_CONTACTS',
    ACCESS_UDMF: 'ohos.permission.ACCESS_UDMF_DATA'
  }
  
  // 檢查並申請權限
  async checkAndRequestPermissions(permissions: string[]): Promise<boolean> {
    for (const permission of permissions) {
      const grantStatus = await abilityAccessCtrl.verifyAccessToken(
        getContext(this).tokenId, 
        permission
      )
      
      if (grantStatus !== 0) { // 0表示已授權
        const grantResult = await abilityAccessCtrl.requestPermissionsFromUser(
          getContext(this), 
          [permission]
        )
        
        if (grantResult.authResults[0] !== 0) {
          return false
        }
      }
    }
    return true
  }
  
  // 數據提供方權限驗證
  validateCallerPermission(): boolean {
    const callerUid = this.getCallingUid()
    const callerPid = this.getCallingPid()
    
    // 驗證調用方身份和權限
    return this.isTrustedCaller(callerUid, callerPid)
  }
}

2. 數據安全策略與加密

// 數據安全處理
class DataSecurityHandler {
  // 敏感數據加密
  async encryptSensitiveData(data: any): Promise<string> {
    const crypto = await crypto.createCrypto('AES256_GCM')
    const plainText = JSON.stringify(data)
    const cipherText = await crypto.encrypt({
      data: new Uint8Array(plainText.split('').map(c => c.charCodeAt(0))),
      key: this.getEncryptionKey()
    })
    return btoa(String.fromCharCode(...cipherText))
  }
  
  // 數據傳輸安全
  async secureDataTransfer(data: any, targetApp: string): Promise<TransferResult> {
    // 驗證目標應用簽名
    await this.verifyTargetApp(targetApp)
    
    // 加密傳輸數據
    const encryptedData = await this.encryptSensitiveData(data)
    
    // 安全通道傳輸
    return await this.transferViaSecureChannel(encryptedData, targetApp)
  }
}
六、性能優化與最佳實踐

大規模數據共享場景下的性能優化策略。

1. 性能優化技巧

@Component
struct PerformanceOptimization {
  private dataShareHelper: dataShare.DataShareHelper | null = null
  
  // 批量操作優化
  async optimizedBatchOperations(operations: DataOperation[]): Promise<void> {
    // 使用事務包裝批量操作
    await this.dataShareHelper.beginTransaction()
    
    try {
      for (const op of operations) {
        switch (op.type) {
          case 'insert':
            await this.dataShareHelper.insert(op.uri, op.data)
            break
          case 'update':
            await this.dataShareHelper.update(op.uri, op.predicates, op.data)
            break
          case 'delete':
            await this.dataShareHelper.delete(op.uri, op.predicates)
            break
        }
      }
      await this.dataShareHelper.commit()
    } catch (error) {
      await this.dataShareHelper.rollback()
      throw error
    }
  }
  
  // 查詢優化:分頁和字段選擇
  async optimizedQuery(predicates: DataSharePredicates, page: number, pageSize: number): Promise<PagedResult> {
    const offset = (page - 1) * pageSize
    
    predicates.limit(pageSize)
      .offset(offset)
      .orderBy('created_time', 'DESC')
    
    // 只查詢需要的字段
    const columns = ['id', 'name', 'phone'] // 避免SELECT *
    
    const resultSet = await this.dataShareHelper.query(this.CONTACTS_URI, predicates, columns)
    return this.processPagedResult(resultSet, page, pageSize)
  }
  
  // 緩存策略
  private queryCache = new Map<string, { data: any, timestamp: number }>()
  private readonly CACHE_TTL = 5 * 60 * 1000 // 5分鐘緩存
  
  async queryWithCache(predicates: DataSharePredicates): Promise<any> {
    const cacheKey = this.generateCacheKey(predicates)
    const cached = this.queryCache.get(cacheKey)
    
    if (cached && (Date.now() - cached.timestamp) < this.CACHE_TTL) {
      return cached.data
    }
    
    const freshData = await this.dataShareHelper.query(this.CONTACTS_URI, predicates, ['*'])
    this.queryCache.set(cacheKey, { data: freshData, timestamp: Date.now() })
    
    return freshData
  }
}
七、實戰案例:企業通訊錄共享系統

以下是一個完整的企業通訊錄共享系統實現。

1. 系統架構設計

// 企業通訊錄數據模型
interface EnterpriseContact {
  id: number
  employeeId: string
  name: string
  department: string
  title: string
  workPhone: string
  workEmail: string
  mobile: string
  avatar?: string
  status: 'active' | 'inactive'
  securityLevel: 1 | 2 | 3 // 數據安全等級
}

// 數據提供方實現
export default class EnterpriseContactProvider extends Extension {
  private readonly TABLE_NAME = 'enterprise_contacts'
  
  onQuery(uri: string, predicates: DataSharePredicates, columns: string[], callback: Function): void {
    // 企業級權限驗證
    if (!this.validateEnterprisePermission()) {
      callback(new Error('企業權限驗證失敗'))
      return
    }
    
    // 根據用户角色過濾數據
    const filteredPredicates = this.applySecurityFilter(predicates)
    
    this.rdbStore.query(this.TABLE_NAME, filteredPredicates, columns, (err, resultSet) => {
      if (err) {
        callback(err)
      } else {
        // 記錄審計日誌
        this.logAccessAudit()
        callback(undefined, resultSet)
      }
    })
  }
  
  // 安全數據過濾
  private applySecurityFilter(predicates: DataSharePredicates): DataSharePredicates {
    const userSecurityLevel = this.getUserSecurityLevel()
    
    // 只能查看同級或更低安全級別的數據
    predicates.lessThanOrEqualTo('securityLevel', userSecurityLevel)
    
    return predicates
  }
}

2. 多應用協同場景

@Entry
@Component
struct EnterpriseContactApp {
  private contactProvider: EnterpriseContactProvider | null = null
  
  // 通訊錄與郵件應用集成
  async shareContactToEmail(contact: EnterpriseContact, emailApp: string): Promise<void> {
    const vCard = this.generateVCard(contact)
    
    const shareRecord: UnifiedRecord = {
      type: UDMFDataType.PLAIN_TEXT,
      details: {
        content: vCard,
        mimeType: 'text/vcard'
      },
      properties: {
        subject: `聯繫人: ${contact.name}`,
        category: 'contact'
      }
    }
    
    await this.udmf.shareToUDMF(shareRecord, {
      allowedApps: [emailApp],
      accessPolicy: { read: true, write: false, share: false }
    })
    
    await this.launchEmailAppWithContact()
  }
  
  // 組織架構同步
  async syncDepartmentStructure(departmentId: string): Promise<void> {
    const predicates = new dataSharePredicates.DataSharePredicates()
    predicates.equalTo('department', departmentId)
      .equalTo('status', 'active')
    
    const departmentContacts = await this.contactProvider.queryContacts(predicates)
    
    // 同步到組織架構應用
    await this.syncToOrgChartApp(departmentId, departmentContacts)
  }
}
💎 總結

跨應用數據共享是鴻蒙分佈式生態的核心能力,通過DataShare和UDMF的有機結合,開發者可以構建出真正實現應用協同的智能體驗。關鍵在於理解安全權限控制、掌握性能優化技巧、遵循標準化數據規範,從而在保障用户隱私的前提下,實現數據的自由流動和價值最大化。

進一步學習建議:在實際項目中,建議從簡單的數據分享場景開始,逐步擴展到複雜的跨應用協同。官方文檔中的DataShare開發指南提供了完整的API參考。