# Flutter实现仿微信分享功能的示例代码详解 本文将全面讲解如何使用Flutter实现仿微信的分享功能,包含UI构建、平台交互、多端适配等完整实现方案。 ## 一、功能需求分析 微信分享功能主要包含以下核心要素: 1. **分享入口**: - 右上角"..."菜单触发 - 长按内容触发 - 特定按钮点击触发 2. **分享面板UI**: - 半透明模态弹窗 - 应用图标网格布局 - 取消按钮 3. **分享目标**: - 微信好友 - 朋友圈 - QQ - 微博 - 复制链接 - 更多... 4. **平台能力**: - 调用原生分享API - 处理分享回调 - 未安装应用处理 ## 二、项目结构与依赖配置 ### 1. 创建Flutter项目 ```bash flutter create wechat_share_demo
pubspec.yaml
配置:
dependencies: flutter: sdk: flutter # 分享插件 share_plus: ^7.0.2 # 平台设备信息 device_info_plus: ^9.0.3 # 权限处理 permission_handler: ^10.4.0 # 图标库 font_awesome_flutter: ^10.5.0 # 路由管理 go_router: ^12.0.0
share_sheet.dart
:
import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; class ShareSheet extends StatelessWidget { final VoidCallback onCancel; final Function(String) onShare; const ShareSheet({ super.key, required this.onCancel, required this.onShare, }); @override Widget build(BuildContext context) { return SafeArea( child: Container( decoration: BoxDecoration( color: Colors.white, borderRadius: const BorderRadius.vertical(top: Radius.circular(12)), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.2), blurRadius: 10, spreadRadius: 0, ) ], ), child: Column( mainAxisSize: MainAxisSize.min, children: [ _buildHeader(), _buildPlatformGrid(), _buildActionRow(), _buildCancelButton(), ], ), ), ); } Widget _buildHeader() { return const Padding( padding: EdgeInsets.symmetric(vertical: 16), child: Text( '分享到', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black87, ), ), ); } Widget _buildPlatformGrid() { const platforms = [ {'name': '微信好友', 'icon': FontAwesomeIcons.weixin, 'color': Colors.green}, {'name': '朋友圈', 'icon': FontAwesomeIcons.users, 'color': Colors.green}, {'name': 'QQ', 'icon': FontAwesomeIcons.qq, 'color': Colors.blue}, {'name': '微博', 'icon': FontAwesomeIcons.weibo, 'color': Colors.orange}, {'name': '复制链接', 'icon': Icons.link, 'color': Colors.grey}, {'name': '更多', 'icon': Icons.more_horiz, 'color': Colors.grey}, ]; return GridView.count( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), crossAxisCount: 4, padding: const EdgeInsets.symmetric(horizontal: 16), children: platforms.map((platform) { return _buildPlatformItem( platform['icon'] as IconData, platform['name'] as String, platform['color'] as Color, ); }).toList(), ); } Widget _buildPlatformItem(IconData icon, String name, Color color) { return GestureDetector( onTap: () => onShare(name), child: Padding( padding: const EdgeInsets.symmetric(vertical: 12), child: Column( children: [ Container( width: 50, height: 50, decoration: BoxDecoration( color: color.withOpacity(0.1), shape: BoxShape.circle, ), child: Icon(icon, color: color, size: 24), ), const SizedBox(height: 8), Text( name, style: const TextStyle(fontSize: 12), ), ], ), ), ); } Widget _buildActionRow() { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Row( children: [ Expanded( child: OutlinedButton( style: OutlinedButton.styleFrom( foregroundColor: Colors.grey, side: const BorderSide(color: Colors.grey), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), ), onPressed: () => onShare('收藏'), child: const Text('收藏'), ), ), const SizedBox(width: 12), Expanded( child: OutlinedButton( style: OutlinedButton.styleFrom( foregroundColor: Colors.grey, side: const BorderSide(color: Colors.grey), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), onPressed: () => onShare('保存图片'), child: const Text('保存图片'), ), ), ], ), ); } Widget _buildCancelButton() { return Container( decoration: const BoxDecoration( border: Border(top: BorderSide(color: Colors.grey, width: 0.5)), ), child: ListTile( title: const Center( child: Text( '取消', style: TextStyle(fontSize: 16), ), ), onTap: onCancel, ), ); } }
share_service.dart
:
import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/services.dart'; import 'package:share_plus/share_plus.dart'; class ShareService { static Future<void> shareToWeChat(String content) async { try { // 检测是否安装微信 final deviceInfo = await DeviceInfoPlugin().androidInfo; if (deviceInfo is AndroidDeviceInfo) { // Android平台处理 const platform = MethodChannel('com.example/share'); await platform.invokeMethod('shareToWeChat', {'text': content}); } else { // iOS平台处理 await Share.share(content, subject: '微信分享'); } } on PlatformException catch (e) { print('分享失败: ${e.message}'); // 处理未安装微信的情况 await Share.share(content); } } static Future<void> shareToWeChatMoments(String content) async { // 类似微信好友的实现,调用不同平台方法 } static Future<void> shareToQQ(String content) async { // QQ分享实现 } static Future<void> copyLink(String link) async { await Clipboard.setData(ClipboardData(text: link)); } static Future<void> saveImage(String imageUrl) async { // 图片保存实现 } }
android/app/src/main/kotlin/com/example/wechat_share_demo/MainActivity.kt
:
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel class MainActivity: FlutterActivity() { private val CHANNEL = "com.example/share" override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> when (call.method) { "shareToWeChat" -> { val text = call.argument<String>("text") // 调用微信SDK分享 shareToWeChat(text ?: "", result) } else -> result.notImplemented() } } } private fun shareToWeChat(text: String, result: MethodChannel.Result) { try { // 实际调用微信SDK的代码 result.success(true) } catch (e: Exception) { result.error("UNAVLABLE", "微信未安装", null) } } }
ios/Runner/AppDelegate.swift
:
import Flutter import UIKit @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { let controller : FlutterViewController = window?.rootViewController as! FlutterViewController let shareChannel = FlutterMethodChannel(name: "com.example/share", binaryMessenger: controller.binaryMessenger) shareChannel.setMethodCallHandler({ (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in guard call.method == "shareToWeChat" else { result(FlutterMethodNotImplemented) return } self.shareToWeChat(arguments: call.arguments, result: result) }) GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } private func shareToWeChat(arguments: Any?, result: FlutterResult) { // 调用微信SDK分享 result(true) } }
main_page.dart
:
import 'package:flutter/material.dart'; import 'package:wechat_share_demo/share_sheet.dart'; import 'package:wechat_share_demo/share_service.dart'; class MainPage extends StatelessWidget { const MainPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('微信分享示例'), actions: [ IconButton( icon: const Icon(Icons.share), onPressed: () => _showShareSheet(context), ), ], ), body: Center( child: ElevatedButton( child: const Text('分享内容'), onPressed: () => _showShareSheet(context), ), ), ); } void _showShareSheet(BuildContext context) { showModalBottomSheet( context: context, backgroundColor: Colors.transparent, isScrollControlled: true, builder: (context) => ShareSheet( onCancel: () => Navigator.pop(context), onShare: (platform) => _handleShare(platform, context), ), ); } Future<void> _handleShare(String platform, BuildContext context) async { Navigator.pop(context); const shareContent = '这是要分享的内容\nhttps://example.com'; const shareImage = 'https://example.com/image.jpg'; switch (platform) { case '微信好友': await ShareService.shareToWeChat(shareContent); break; case '朋友圈': await ShareService.shareToWeChatMoments(shareContent); break; case 'QQ': await ShareService.shareToQQ(shareContent); break; case '微博': // 微博分享实现 break; case '复制链接': await ShareService.copyLink('https://example.com'); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('链接已复制')), ); break; case '保存图片': await ShareService.saveImage(shareImage); break; default: await Share.share(shareContent); } } }
main.dart
:
import 'package:flutter/material.dart'; import 'package:wechat_share_demo/main_page.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: '微信分享示例', theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: const MainPage(), ); } }
class SharePreview extends StatelessWidget { final String title; final String description; final String imageUrl; final String url; const SharePreview({ super.key, required this.title, required this.description, required this.imageUrl, required this.url, }); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(8), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ if (imageUrl.isNotEmpty) ClipRRect( borderRadius: BorderRadius.circular(4), child: Image.network( imageUrl, height: 120, width: double.infinity, fit: BoxFit.cover, ), ), const SizedBox(height: 12), Text( title, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), const SizedBox(height: 4), Text( description, style: TextStyle( color: Colors.grey[600], fontSize: 14, ), ), const SizedBox(height: 8), Text( url, style: TextStyle( color: Colors.blue[400], fontSize: 12, ), ), ], ), ); } }
class ShareAnalytics { static void logShareEvent({ required String platform, required String contentType, required bool success, }) { // 实际项目中调用埋点SDK debugPrint(''' 分享事件记录: 平台: $platform 类型: $contentType 成功: $success '''); } } // 使用示例 ShareAnalytics.logShareEvent( platform: '微信好友', contentType: '链接', success: true, );
class ShareLocalizations { final Locale locale; ShareLocalizations(this.locale); static ShareLocalizations of(BuildContext context) { return Localizations.of<ShareLocalizations>(context, ShareLocalizations)!; } static const Map<String, Map<String, String>> _localizedValues = { 'en': { 'shareTo': 'Share to', 'wechat': 'WeChat', 'moments': 'Moments', 'cancel': 'Cancel', }, 'zh': { 'shareTo': '分享到', 'wechat': '微信好友', 'moments': '朋友圈', 'cancel': '取消', }, }; String get shareTo => _localizedValues[locale.languageCode]!['shareTo']!; String get wechat => _localizedValues[locale.languageCode]!['wechat']!; String get moments => _localizedValues[locale.languageCode]!['moments']!; String get cancel => _localizedValues[locale.languageCode]!['cancel']!; }
class OptimizedShareSheet extends StatefulWidget { // ...参数相同 @override State<OptimizedShareSheet> createState() => _OptimizedShareSheetState(); } class _OptimizedShareSheetState extends State<OptimizedShareSheet> { late final List<Map<String, dynamic>> _platforms; @override void initState() { super.initState(); // 提前初始化数据,避免重复构建 _platforms = const [ {'name': '微信好友', 'icon': FontAwesomeIcons.weixin, 'color': Colors.green}, // ...其他平台数据 ]; } @override Widget build(BuildContext context) { return SafeArea( child: Column( children: [ // 使用ListView.builder优化长列表 GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, childAspectRatio: 0.8, ), itemCount: _platforms.length, itemBuilder: (context, index) { final platform = _platforms[index]; return _buildPlatformItem( platform['icon'] as IconData, platform['name'] as String, platform['color'] as Color, ); }, ), // ...其他组件 ], ), ); } }
share_sheet_test.dart
:
”`dart import ‘package:flutter/material.dart’; import ‘package:flutter_test/flutter_test.dart’; import ‘package:wechat_share_demo/share_sheet.dart’;
void main() { testWidgets(‘分享面板显示测试’, (WidgetTester tester) async { bool canceled = false; String? sharedPlatform;
await tester.pumpWidget(MaterialApp( home: Scaffold( body: ShareSheet( onCancel: () => canceled = true, onShare: (platform) => sharedPlatform = platform, ), ), )); // 验证标题显示 expect(find.text('分享到'), finds
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。