HarmonyOS鸿蒙Next中如何在应用中实现分享功能?

HarmonyOS鸿蒙Next中如何在应用中实现分享功能? 鸿蒙应用可以通过系统分享功能分享内容,本文介绍如何使用 plus.share API 实现文本、图片、链接等内容的分享功能。

3 回复

一、分享功能架构设计

1. 分享类型支持

  • 文本分享
  • 图片分享
  • 链接分享
  • 多类型混合分享

2. 分享目标

  • 系统分享面板
  • 微信/QQ/微博等
  • 复制到剪贴板
  • 保存到相册

二、基础分享实现

1. 创建分享工具(utils/share.js)

/**
 * 分享功能工具
 * 支持文本、图片、链接等分享
 */

/**
 * 分享文本
 * @param {String} text 分享文本
 * @param {Object} options 配置选项
 * @returns {Promise<Object>} 分享结果
 */
export async function shareText(text, options = {}) {
    const {
        title = '分享',
        success = null,
        fail = null
    } = options
    
    return new Promise((resolve, reject) => {
        // #ifdef APP-HARMONY
        try {
            // 使用 plus.share 分享文本
            const shareService = plus.share.getServices((services) => {
                if (services && services.length > 0) {
                    // 显示分享选择器
                    plus.share.sendWithSystem({
                        type: 'text',
                        content: text,
                        title: title,
                        success: (result) => {
                            console.log('分享成功:', result)
                            if (success) success(result)
                            resolve({
                                success: true,
                                result: result
                            })
                        },
                        fail: (error) => {
                            console.error('分享失败:', error)
                            if (fail) fail(error)
                            reject(error)
                        }
                    })
                } else {
                    // 降级方案:复制到剪贴板
                    copyToClipboard(text)
                    resolve({
                        success: true,
                        method: 'clipboard'
                    })
                }
            }, (error) => {
                console.error('获取分享服务失败:', error)
                // 降级方案
                copyToClipboard(text)
                resolve({
                    success: true,
                    method: 'clipboard'
                })
            })
        } catch (error) {
            console.error('分享文本失败:', error)
            // 降级方案
            copyToClipboard(text)
            resolve({
                success: true,
                method: 'clipboard'
            })
        }
        // #endif
        
        // #ifndef APP-HARMONY
        // H5 或其他平台使用 Web Share API
        if (navigator.share) {
            navigator.share({
                title: title,
                text: text
            }).then(() => {
                if (success) success()
                resolve({ success: true })
            }).catch((error) => {
                if (fail) fail(error)
                reject(error)
            })
        } else {
            // 降级方案
            copyToClipboard(text)
            resolve({
                success: true,
                method: 'clipboard'
            })
        }
        // #endif
    })
}

/**
 * 分享图片
 * @param {String} imagePath 图片路径(本地路径或网络路径)
 * @param {Object} options 配置选项
 * @returns {Promise<Object>} 分享结果
 */
export async function shareImage(imagePath, options = {}) {
    const {
        title = '分享图片',
        description = '',
        success = null,
        fail = null
    } = options
    
    return new Promise((resolve, reject) => {
        // #ifdef APP-HARMONY
        try {
            // 如果是网络图片,先下载到本地
            if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) {
                downloadImage(imagePath).then(localPath => {
                    shareLocalImage(localPath, options)
                        .then(resolve)
                        .catch(reject)
                }).catch(reject)
            } else {
                shareLocalImage(imagePath, options)
                    .then(resolve)
                    .catch(reject)
            }
        } catch (error) {
            console.error('分享图片失败:', error)
            if (fail) fail(error)
            reject(error)
        }
        // #endif
        
        // #ifndef APP-HARMONY
        // H5 平台
        if (navigator.share && navigator.canShare) {
            // 需要将图片转换为 File 对象
            imageToFile(imagePath).then(file => {
                navigator.share({
                    title: title,
                    text: description,
                    files: [file]
                }).then(() => {
                    if (success) success()
                    resolve({ success: true })
                }).catch((error) => {
                    if (fail) fail(error)
                    reject(error)
                })
            }).catch(reject)
        } else {
            // 降级方案:保存到相册
            saveImageToAlbum(imagePath)
                .then(() => {
                    uni.showToast({
                        title: '图片已保存到相册',
                        icon: 'success'
                    })
                    resolve({ success: true, method: 'album' })
                })
                .catch(reject)
        }
        // #endif
    })
}

/**
 * 分享本地图片
 */
function shareLocalImage(imagePath, options) {
    return new Promise((resolve, reject) => {
        // #ifdef APP-HARMONY
        plus.share.sendWithSystem({
            type: 'image',
            pictures: [imagePath],
            title: options.title || '分享图片',
            content: options.description || '',
            success: (result) => {
                console.log('分享图片成功:', result)
                if (options.success) options.success(result)
                resolve({
                    success: true,
                    result: result
                })
            },
            fail: (error) => {
                console.error('分享图片失败:', error)
                if (options.fail) options.fail(error)
                reject(error)
            }
        })
        // #endif
    })
}

/**
 * 分享链接
 * @param {String} url 链接地址
 * @param {Object} options 配置选项
 * @returns {Promise<Object>} 分享结果
 */
export async function shareLink(url, options = {}) {
    const {
        title = '分享链接',
        description = '',
        thumb = '',  // 缩略图
        success = null,
        fail = null
    } = options
    
    return new Promise((resolve, reject) => {
        // #ifdef APP-HARMONY
        try {
            plus.share.sendWithSystem({
                type: 'web',
                href: url,
                title: title,
                content: description,
                thumbs: thumb ? [thumb] : [],
                success: (result) => {
                    console.log('分享链接成功:', result)
                    if (success) success(result)
                    resolve({
                        success: true,
                        result: result
                    })
                },
                fail: (error) => {
                    console.error('分享链接失败:', error)
                    // 降级方案:复制链接
                    copyToClipboard(url)
                    uni.showToast({
                        title: '链接已复制',
                        icon: 'success'
                    })
                    resolve({
                        success: true,
                        method: 'clipboard'
                    })
                }
            })
        } catch (error) {
            console.error('分享链接失败:', error)
            copyToClipboard(url)
            resolve({
                success: true,
                method: 'clipboard'
            })
        }
        // #endif
        
        // #ifndef APP-HARMONY
        if (navigator.share) {
            navigator.share({
                title: title,
                text: description,
                url: url
            }).then(() => {
                if (success) success()
                resolve({ success: true })
            }).catch((error) => {
                if (fail) fail(error)
                copyToClipboard(url)
                resolve({
                    success: true,
                    method: 'clipboard'
                })
            })
        } else {
            copyToClipboard(url)
            resolve({
                success: true,
                method: 'clipboard'
            })
        }
        // #endif
    })
}

/**
 * 分享多类型内容
 * @param {Object} shareData 分享数据
 * @returns {Promise<Object>} 分享结果
 */
export async function shareMultiple(shareData) {
    const {
        text = '',
        image = '',
        url = '',
        title = '分享',
        description = '',
        thumb = ''
    } = shareData
    
    // #ifdef APP-HARMONY
    try {
        const shareOptions = {
            title: title,
            content: description || text,
            success: (result) => {
                console.log('分享成功:', result)
                uni.showToast({
                    title: '分享成功',
                    icon: 'success'
                })
            },
            fail: (error) => {
                console.error('分享失败:', error)
                uni.showToast({
                    title: '分享失败',
                    icon: 'none'
                })
            }
        }
        
        // 根据内容类型设置
        if (url) {
            shareOptions.type = 'web'
            shareOptions.href = url
            if (thumb) {
                shareOptions.thumbs = [thumb]
            }
        } else if (image) {
            shareOptions.type = 'image'
            shareOptions.pictures = [image]
        } else if (text) {
            shareOptions.type = 'text'
            shareOptions.content = text
        }
        
        return new Promise((resolve, reject) => {
            plus.share.sendWithSystem(shareOptions)
        })
    } catch (error) {
        console.error('分享失败:', error)
        throw error
    }
    // #endif
}

三、辅助功能实现

2. 辅助工具函数

/**
 * 复制到剪贴板
 * @param {String} text 文本内容
 * @returns {Promise<Boolean>} 是否成功
 */
export function copyToClipboard(text) {
    return new Promise((resolve, reject) => {
        uni.setClipboardData({
            data: text,
            success: () => {
                uni.showToast({
                    title: '已复制',
                    icon: 'success'
                })
                resolve(true)
            },
            fail: (error) => {
                console.error('复制失败:', error)
                reject(error)
            }
        })
    })
}

/**
 * 下载网络图片到本地
 * @param {String} imageUrl 图片 URL
 * @returns {Promise<String>} 本地路径
 */
function downloadImage(imageUrl) {
    return new Promise((resolve, reject) => {
        uni.downloadFile({
            url: imageUrl,
            success: (res) => {
                if (res.statusCode === 200) {
                    resolve(res.tempFilePath)
                } else {
                    reject(new Error('下载失败'))
                }
            },
            fail: (error) => {
                reject(error)
            }
        })
    })
}

/**
 * 保存图片到相册
 * @param {String} imagePath 图片路径
 * @returns {Promise<Boolean>} 是否成功
 */
export function saveImageToAlbum(imagePath) {
    return new Promise((resolve, reject) => {
        // #ifdef APP-HARMONY
        // 先保存到本地
        if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) {
            downloadImage(imagePath).then(localPath => {
                saveLocalImageToAlbum(localPath)
                    .then(resolve)
                    .catch(reject)
            }).catch(reject)
        } else {
            saveLocalImageToAlbum(imagePath)
                .then(resolve)
                .catch(reject)
        }
        // #endif
        
        // #ifndef APP-HARMONY
        // H5 平台需要用户手动保存
        uni.showModal({
            title: '保存图片',
            content: '请长按图片保存',
            showCancel: false
        })
        resolve(true)
        // #endif
    })
}

/**
 * 保存本地图片到相册
 */
function saveLocalImageToAlbum(imagePath) {
    return new Promise((resolve, reject) => {
        // #ifdef APP-HARMONY
        plus.gallery.save(
            imagePath,
            () => {
                resolve(true)
            },
            (error) => {
                console.error('保存图片失败:', error)
                reject(error)
            }
        )
        // #endif
        
        // #ifndef APP-HARMONY
        resolve(true)
        // #endif
    })
}

/**
 * 生成分享图片(用于分享健康报告等)
 * @param {Object} data 数据
 * @returns {Promise<String>} 图片路径
 */
export async function generateShareImage(data) {
    // 使用 canvas 生成分享图片
    return new Promise((resolve, reject) => {
        // 这里需要使用 canvas API 生成图片
        // 具体实现根据需求定制
        const ctx = uni.createCanvasContext('shareCanvas')
        
        // 绘制背景
        ctx.setFillStyle('#FFFFFF')
        ctx.fillRect(0, 0, 750, 1334)
        
        // 绘制内容
        ctx.setFillStyle('#333333')
        ctx.setFontSize(32)
        ctx.fillText(data.title || '健康报告', 40, 100)
        
        // ... 更多绘制内容
        
        // 导出图片
        ctx.draw(false, () => {
            uni.canvasToTempFilePath({
                canvasId: 'shareCanvas',
                success: (res) => {
                    resolve(res.tempFilePath)
                },
                fail: reject
            })
        })
    })
}

四、分享组件实现

3. 分享组件(components/share-panel/share-panel.vue)

<template>
    <view class="share-panel-mask" v-if="visible" @tap="handleMaskTap">
        <view class="share-panel" @tap.stop>
            <view class="panel-header">
                <text class="panel-title">分享到</text>
                <text class="panel-close" @tap="handleClose">×</text>
            </view>
            
            <view class="panel-content">
                <scroll-view scroll-y class="share-options">
                    <!-- 系统分享 -->
                    <view class="share-option" @tap="handleSystemShare">
                        <view class="option-icon system-icon">📤</view>
                        <text class="option-text">系统分享</text>
                    </view>
                    
                    <!-- 复制链接 -->
                    <view class="share-option" @tap="handleCopyLink" v-if="shareData.url">
                        <view class="option-icon copy-icon">🔗</view>
                        <text class="option-text">复制链接</text>
                    </view>
                    
                    <!-- 复制文本 -->
                    <view class="share-option" @tap="handleCopyText" v-if="shareData.text">
                        <view class="option-icon copy-icon">📋</view>
                        <text class="option-text">复制文本</text>
                    </view>
                    
                    <!-- 保存图片 -->
                    <view class="share-option" @tap="handleSaveImage" v-if="shareData.image">
                        <view class="option-icon save-icon">💾</view>
                        <text class="option-text">保存图片</text>
                    </view>
                    
                    <!-- 生成分享图 -->
                    <view class="share-option" @tap="handleGenerateImage" v-if="shareData.generateImage">
                        <view class="option-icon generate-icon">🖼️</view>
                        <text class="option-text">生成分享图</text>
                    </view>
                </scroll-view>
            </view>
        </view>
    </view>
</template>

<script>
import { 
    shareText, 
    shareImage, 
    shareLink, 
    shareMultiple,
    copyToClipboard,
    saveImageToAlbum,
    generateShareImage
} from '@/utils/share.js'

export default {
    name: 'SharePanel',
    props: {
        visible: {
            type: Boolean,
            default: false
        },
        shareData: {
            type: Object,
            default: () => ({
                text: '',
                image: '',
                url: '',
                title: '',
                description: '',
                thumb: ''
            })
        }
    },
    methods: {
        handleMaskTap() {
            this.handleClose()
        },
        handleClose() {
            this.$emit('close')
        },
        
        // 系统分享
        async handleSystemShare() {
            try {
                let result
                if (this.shareData.url) {
                    result = await shareLink(this.shareData.url, {
                        title: this.shareData.title,
                        description: this.shareData.description,
                        thumb: this.shareData.thumb
                    })
                } else if (this.shareData.image) {
                    result = await shareImage(this.shareData.image, {
                        title: this.shareData.title,
                        description: this.shareData.description
                    })
                } else if (this.shareData.text) {
                    result = await shareText(this.shareData.text, {
                        title: this.shareData.title
                    })
                } else {
                    result = await shareMultiple(this.shareData)
                }
                
                if (result.success) {
                    this.handleClose()
                    this.$emit('success', result)
                }
            } catch (error) {
                console.error('分享失败:', error)
                uni.showToast({
                    title: '分享失败',
                    icon: 'none'
                })
            }
        },
        
        // 复制链接
        async handleCopyLink() {
            try {
                await copyToClipboard(this.shareData.url)
                this.handleClose()
                this.$emit('success', { method: 'copyLink' })
            } catch (error) {
                console.error('复制失败:', error)
            }
        },
        
        // 复制文本
        async handleCopyText() {
            try {
                await copyToClipboard(this.shareData.text)
                this.handleClose()
                this.$emit('success', { method: 'copyText' })
            } catch (error) {
                console.error('复制失败:', error)
            }
        },
        
        // 保存图片
        async handleSaveImage() {
            try {
                uni.showLoading({
                    title: '保存中...',
                    mask: true
                })
                
                await saveImageToAlbum(this.shareData.image)
                
                uni.hideLoading()
                this.handleClose()
                this.$emit('success', { method: 'saveImage' })
            } catch (error) {
                uni.hideLoading()
                console.error('保存失败:', error)
                uni.showToast({
                    title: '保存失败',
                    icon: 'none'
                })
            }
        },
        
        // 生成分享图
        async handleGenerateImage() {
            try {
                uni.showLoading({
                    title: '生成中...',
                    mask: true
                })

更多关于HarmonyOS鸿蒙Next中如何在应用中实现分享功能?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,应用分享功能主要通过Share模块实现。使用ShareAction类创建分享意图,设置分享内容(如文本、链接、文件等)。通过show()方法触发系统分享面板,用户可选择目标应用进行分享。分享数据需符合系统定义的ShareData格式。

在HarmonyOS Next中,应用可以通过系统分享功能实现内容分享。以下是使用plus.share API实现分享功能的核心步骤:

  1. 导入模块:在代码中导入@kit.ShareKit模块。
  2. 创建分享器:使用ShareKit.getShareService()获取系统分享服务。
  3. 配置分享内容:构建ShareOption对象,设置分享的标题、文本、链接或图片URI等。
  4. 调用分享:调用share()方法触发系统分享面板,用户可选择目标应用进行分享。

示例代码(文本分享)

import shareKit from '@kit.ShareKit';

let shareService = shareKit.getShareService();
let shareOption = {
  title: '分享标题',
  text: '这是分享的文本内容。',
  link: 'https://example.com'
};
shareService.share(shareOption).then(() => {
  console.log('分享成功');
}).catch((err) => {
  console.error('分享失败: ' + err);
});

关键点

  • 分享图片时需将图片路径转换为URI格式(如dataability://file://)。
  • 系统分享面板会自动适配可用应用(如邮件、社交软件)。
  • 分享操作依赖用户界面交互触发。

此方式无需处理具体应用逻辑,由系统统一调度,符合HarmonyOS Next的安全与体验规范。

回到顶部