手头上的一个游戏项目需要实现截屏并分享到Facebook的功能,但Facebook Unity SDK提供的两个接口:FB.FeedShare() 和 FB.ShareLink,前者会弹出一个Web登录提示框,用户需要登录后才能分享,用户体验流程繁琐。后者虽然不需要登录就可以调用Facebook原生的分享对话框,但只能分享链接不能直接分享本地图片。这意味着如何要实现将屏幕截图分享到Facebook的功能,我们需要先将本地截屏的图片上传到某个图床,获取图片的链接然后再调用FB.ShareLink() 才行。这个方法虽然勉强也可以实现分享图片的功能,但过程仍然繁琐,而且分享到Facebook的图片是以外链网页的缩略图方式展示的,要查看全图还要再次点击打开,也不大符合我们的要求。进一步研究了Facebook SDK的文档,发现iOS SDK提供了直接调用Facebook原生对话框分享图片的功能,于是有了下面的Objectiv-C插件的解决方案。

1 开始之前

开始之前,请下载并导入最新版本的Facebook SDK for Unity https://developers.facebook.com/docs/unity/downloads/
本文中的代码在Unity3D 2019.3.6f 以及Xcode 11.3.1中调试通过。

2 在Assets/Plugins/iOS目录下创建Objective-C插件

我们需要创建三个文件放在Assets/Plugins/iOS目录下,这样在Unity打包输出xcode工程项目时会自动将文件拷贝到工程的Libraries/Plugins/iOS目录并添加正确的引用。这三个文件的作用分别如下:
  • NativeFBShareDelegate.h : 定义继承自FBSDKSharingDelegate的回调接口,接受Facebook原生对话框分享成功、取消、错误消息回调。
  • NativeFBShareDelegate.m :回调接口的实现代码,收到Facebook原生对话框分享的消息回调后,使用UnitySendMessage() 方法把结果发送给Unity C#脚本。
  • NativeFBShare.mm :定义C#中调用的Native Plugin接口方法,调用Facebook iOS SDK打开原生分享对话框(注意这个文件的后缀名要使用.mm)
<u> NativeFBShareDelegate.h 源代码 </u>
    
#import <FBSDKShareKit/FBSDKShareKit.h> @ interface NativeFBShareDelegate : NSObject < FBSDKSharingDelegate > + ( instancetype ) instanceWithRequestID : ( int ) requestID ; @end
<u> NativeFBShareDelegate.m 源代码 </u>
    
#import <Foundation/Foundation.h> #import "NativeFBShareDelegate.h" #import "FBUnityUtility.h" #import "UnityInterface.h" //Unity 中接收回调消息的游戏对象名称 const char * const GAME_OBJECT_NAME = "FBShareButton" ; //Unity 中处理回调消息的方法名称 const char * const FBUnityMethodName_OnFacebookShareNativeCallback = "OnFacebookShareNativeCallback" ; static NSMutableArray * g_instances ; @implementation NativeFBShareDelegate { int _requestID ; } + ( void ) initialize { if ( self == [ NativeFBShareDelegate class ] ) { g_instances = [ NSMutableArray array ] ; } } - ( void ) complete { [ g_instances removeObject : self ] ; } + ( instancetype ) instanceWithRequestID : ( int ) requestID { NativeFBShareDelegate * instance = [ [ NativeFBShareDelegate alloc ] init ] ; instance -> _requestID = requestID ; [ g_instances addObject : instance ] ; return instance ; } # pragma mark - FBSDKSharingDelegate - ( void ) sharer : ( id < FBSDKSharing > ) sharer didCompleteWithResults : ( NSDictionary * ) results { NSLog ( @"FBShareComplete" ) ; //分享成功,返回字符串“success” UnitySendMessage ( GAME_OBJECT_NAME , FBUnityMethodName_OnFacebookShareNativeCallback , "success" ) ; [ self complete ] ; } - ( void ) sharer : ( id < FBSDKSharing > ) sharer didFailWithError : ( NSError * ) error { NSLog ( @"FBShareError" ) ; //分享发生错误时,返回字符串“error” UnitySendMessage ( GAME_OBJECT_NAME , FBUnityMethodName_OnFacebookShareNativeCallback , "error" ) ; [ self complete ] ; } - ( void ) sharerDidCancel : ( id < FBSDKSharing > ) sharer { NSLog ( @"FBShareCancelled" ) ; //用户取消了分享,返回字符串“cancelled” UnitySendMessage ( GAME_OBJECT_NAME , FBUnityMethodName_OnFacebookShareNativeCallback , "cancelled" ) ; [ self complete ] ; } @end
<u> NativeFBShare.mm 源代码</u>
    
#import <FBSDKShareKit/FBSDKShareKit.h> #import "FBUnitySDKDelegate.h" #import "FBUnityUtility.h" #import "NativeFBShareDelegate.h" #ifdef UNITY_4_0 || UNITY_5_0 #import "iPhone_View.h" # else extern UIViewController * UnityGetGLViewController ( ) ; # endif extern "C" void _NativeFacebookShare ( const char * imagePath ) { NSString * imgPath = [ [ NSString alloc ] initWithUTF8String : imagePath ] ; NSLog ( @"_NativeFacebookShare local image path: %@" , imgPath ) ; UIImage * image = [ UIImage imageWithContentsOfFile : imgPath ] ; FBSDKSharePhoto * photo = [ [ FBSDKSharePhoto alloc ] init ] ; photo . image = image ; photo . userGenerated = YES ; FBSDKSharePhotoContent * content = [ [ FBSDKSharePhotoContent alloc ] init ] ; content . photos = @ [ photo ] ; UIViewController * rootViewController = UnityGetGLViewController ( ) ; FBSDKShareDialog * dialog = [ [ FBSDKShareDialog alloc ] init ] ; dialog . fromViewController = rootViewController ; dialog . shareContent = content ; dialog . mode = FBSDKShareDialogModeAutomatic ; NativeFBShareDelegate * delegate = [ NativeFBShareDelegate instanceWithRequestID : 1 ] ; dialog . delegate = delegate ; NSError * error ; if ( ! [ dialog validateWithError : & error ] ) { [ FBUnityUtility sendErrorToUnity : FBUnityMessageName_OnShareLinkComplete error : error requestId : 1 ] ; } if ( ! [ dialog show ] ) { [ FBUnityUtility sendErrorToUnity : FBUnityMessageName_OnShareLinkComplete errorMessage : @"Failed to show share dialog_" requestId : 1 ] ; } }

3 在Unity 中调用Facebook的原生分享对话框

在Unity中,可以用下面的C#代码调用刚才实现的iOS原生插件接口:
    
# if UNITY_IOS || UNITY_IPHONE [ System . Runtime . InteropServices . DllImport ( "__Internal" ) ] private static extern bool _NativeFacebookShare ( string localImagePath ) ; # endif
我们在Unity中创建一个Button,如下图:
注意Button命名为FBShareButton,这个GameObject名字我们稍后还会用到),挂上下面的脚本,即可实现截屏并分享到Facebook的功能。
    
using System . IO ; using System . Collections ; using UnityEngine ; using UnityEngine . UI ; public class FacebookShareButton : MonoBehaviour { void Awake ( ) { GetComponent < Button > ( ) . onClick . AddListener ( _OnButtonClick ) ; } private void _OnButtonClick ( ) { this . transform . localScale = Vector3 . zero ; StartCoroutine ( _ShareOnFacebook ( ) ) ; } private IEnumerator _ShareOnFacebook ( ) { string screenshotFileName = "screenshot.png" ; string screenshotFilePath = Path . Combine ( Application . persistentDataPath , screenshotFileName ) ; ; if ( File . Exists ( screenshotFilePath ) ) { File . Delete ( screenshotFilePath ) ; } yield return new WaitForEndOfFrame ( ) ; ScreenCapture . CaptureScreenshot ( screenshotFileName ) ; while ( ! File . Exists ( screenshotFilePath ) ) { yield return null ; } # if UNITY_IOS || UNITY_IPHONE _NativeFacebookShare ( screenshotFilePath ) ; # elif UNITY_ANDROID //TODO: Calling Android native plugin to share on Facebook # endif } # if UNITY_IOS || UNITY_IPHONE [ System . Runtime . InteropServices . DllImport ( "__Internal" ) ] private static extern bool _NativeFacebookShare ( string localImagePath ) ; # endif
下面是在iPhone真机上运行的结果

4 获取分享结果的回调通知

有时我们需要知道Facebook分享的结果来实现一些功能,比如如果用户分享失败,则弹出对话框让用户重试一遍。为了实现这个功能,我们在 NativeFBShareDelegate.h 和 NativeFBShareDelegate.m 中定义并实现了FBSDKSharingDelegate的回调接口,并在 NativeFBShare.mm 中创建了这个delegate的实例并注册到FBSDKShareDialog,在收到Facebook原生对话框分享的消息回调后,再使用UnitySendMessage() 方法把结果发送给Unity C#脚本。
UnitySendMessage是Unity提供的一个工具方法,可以从iOS Native Plugin向Unity 游戏对象发送消息。这个方法的签名如下:
    
void UnitySendMessage ( const char * obj , const char * method , const char * msg ) ;
其中第一个参数是接受这个消息的游戏对象名称,第二个参数是这个对象上所绑定的脚本接受回调的方法名称,第三个参数是发送的消息内容,只能是字符串。
在本文前面给出的示例代码中
  • 我们接收消息的游戏对象名字为FBShareButton
  • 处理回调消息的方法名称是OnFacebookShareNativeCallback(string)
  • 用户分享成功返回“success”,发生错误返回“error”,取消返回“cancelled”
我们给FacebookShareButton.cs脚本添加OnFacebookShareNativeCallback(string)方法来接收分享结果的回调消息。
    
private Text m_ResultText ; void Start ( ) { m_ResultText = this . transform . Find ( "Text" ) . GetComponent < Text > ( ) ; m_ResultText . text = "" ; } public void OnFacebookShareNativeCallback ( string result ) { Text shareResult = GetComponent < Text > ( ) ; if ( string . Equals ( result , "success" ) ) { shareResult . text = "FB Share Result: Succeed" ; } else if ( string . Equals ( result , "cancelled" ) ) { shareResult . text = "FB Share Result: Cancelled" ; } else { shareResult . text = "FB Share Result: Error" ; } }
下面是在iPhone上运行的结果

5 参考资料

Logo

分享前沿Unity技术干货和开发经验,精彩的Unity活动和社区相关信息

更多推荐