Windows Phone 8和Unity 5支持Facebook SDK

时间:2015-03-10 16:12:53

标签: facebook windows-phone-8 facebook-unity-sdk

这是为Facebook SDK支持WP8和Unity 5的请求。 我是一名想要在许多平台上制作游戏的开发者,能够发布到Windows Phone 8商店是我议程的重要组成部分。

此平台的支持是否计划在短期内发布?如果是这样,你什么时候发布它呢?

此外,是否有即将发布的Unity SDK可用于Unity 5?我已经设法让当前的版本工作,但由于它还没有完全支持,我不知道什么会起作用,什么不起作用。

非常感谢有关这些问题的任何信息!

1 个答案:

答案 0 :(得分:4)

更新:我遇到了这个视频,解释了" AndContinue"方法在Windows 10中消失,所以我们可以使用一种方法; Windows 8 / 8.1 api上已存在的异步方法。请查看https://youtu.be/aFVAP3fNJVo?t=23m34s

我和你在同一个地方但设法让它运转起来。如果我有时间,可能会写一篇关于我的经历的博客。

以下是直接调用WebAuthenticationBroker的一些主要代码: -

    static bool isTryingToRegister { get; set; }
    private static string _FbToken;
    public static string response;
    static bool isLoggedIn { get; set; }
    static private string AppID { get { return "000000000000000000"; } }
    static private Uri callback { get; set; }
    static private string permissions { get { return "public_profile, user_friends, email, publish_actions, user_photos"; } }
    public static System.Action<object> AuthSuccessCallback;
    public static System.Action<object> AuthFailedCallback;
    public static string fbToken
    {
        get
        {
            return _FbToken;
        }
    }

    static Uri loginUrl
    {
        get
        {
            return new Uri(String.Format("https://www.facebook.com/v2.0/dialog/oauth/?client_id={0}&display=popup&response_type=token&redirect_uri={1}&scope={2}",
                AppID,
                callback,
                permissions));
        }
    }

    public static IEnumerator _Run_ConnectWithFacebook()
    {
        yield return new WaitForEndOfFrame();

#if UNITY_EDITOR
        UnityDebugAuthentication();
#endif
#if NETFX_CORE
        WindowsStoreAuthenticate();
#endif

    }
#if NETFX_CORE
    static void WindowsStoreAuthenticate()
    {
#if UNITY_WP_8_1 && !UNITY_EDITOR
        AuthSuccessCallback =  _Run_ConnectWithFacebook_SuccessResponse;
        AuthFailedCallback = _Run_ConnectWithFacebook_FailedResponse;
        UnityEngine.WSA.Application.InvokeOnUIThread(
        () =>
        {
            callback = WebAuthenticationBroker.GetCurrentApplicationCallbackUri();
            WebAuthenticationBroker.AuthenticateAndContinue(loginUrl, callback, null, WebAuthenticationOptions.None);
        }, true);
#endif
#if UNITY_METRO_8_1 && !UNITY_EDITOR
        AuthSuccessCallback = _Run_ConnectWithFacebook_SuccessResponse;
        AuthFailedCallback = _Run_ConnectWithFacebook_FailedResponse;
        UnityEngine.WSA.Application.InvokeOnUIThread(
        async () =>
        {
            callback = WebAuthenticationBroker.GetCurrentApplicationCallbackUri();
            WebAuthenticationResult authResult = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, loginUrl);
        }, true);
#endif
    }
#endif

请注意我如何使用Windows Phone的WebAuthenticationBroker.AuthenticateAndContinue和Windows 8的WebAuthenticationBroker.AuthenticateAsync。这对于各自的平台来说是必需的。您可能想要了解一下WebAuthenticationBroker,这是一个适用于WP8和WSA的Microsoft类(我猜你的目标是WSA,我也是): -

https://msdn.microsoft.com/library/windows/apps/windows.security.authentication.web.webauthenticationbroker.aspx?f=255&MSPPError=-2147217396

您还需要在Unity中构建一个c#项目,这样您就可以实现它的第2部分,其中包括将令牌详细信息返回给应用程序时的处理。这是我的App.xaml.cs代码示例,其灵感来自https://msdn.microsoft.com/en-us/library/dn631755.aspx:-

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using UnityPlayer;
using Template.Common;
using Windows.Security.Authentication.Web;
// The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=234227

namespace Template
{
    /// <summary>
    /// Provides application-specific behavior to supplement the default Application class.
    /// </summary>
    sealed partial class App : Application
    {
        private WinRTBridge.WinRTBridge _bridge;
        private AppCallbacks appCallbacks;
#if UNITY_WP_8_1
        public ContinuationManager continuationManager { get; private set; }
#endif
        /// <summary>
        /// Initializes the singleton application object.  This is the first line of authored code
        /// executed, and as such is the logical equivalent of main() or WinMain().
        /// </summary>
        public App()
        {
            this.InitializeComponent();
            appCallbacks = new AppCallbacks();
            appCallbacks.RenderingStarted += RemoveSplashScreen;

#if UNITY_WP_8_1
            this.Suspending += OnSuspending;
            continuationManager = new ContinuationManager();
#endif
        }

        /// <summary>
        /// Invoked when application is launched through protocol.
        /// Read more - http://msdn.microsoft.com/library/windows/apps/br224742
        /// </summary>
        /// <param name="args"></param>
        protected override void OnActivated(IActivatedEventArgs args)
        {
#if UNITY_WP_8_1

            var continuationEventArgs = args as IContinuationActivatedEventArgs;
            if (continuationEventArgs != null)
            {

                    ContinueWebAuthentication(args as WebAuthenticationBrokerContinuationEventArgs);
                    return;
                //}
            }
#endif
            string appArgs = "";
            Windows.ApplicationModel.Activation.SplashScreen splashScreen = null;
            switch (args.Kind)
            {
                case ActivationKind.Protocol:
                    ProtocolActivatedEventArgs eventArgs = args as ProtocolActivatedEventArgs;
                    splashScreen = eventArgs.SplashScreen;
                    appArgs += string.Format("Uri={0}", eventArgs.Uri.AbsoluteUri);
                    break;
            }
            InitializeUnity(appArgs, splashScreen);
        }


#if UNITY_WP_8_1
        public void ContinueWebAuthentication(WebAuthenticationBrokerContinuationEventArgs args)
        {
            WebAuthenticationResult result = args.WebAuthenticationResult;

            if (result.ResponseStatus == WebAuthenticationStatus.Success)
            {
                string responseData = result.ResponseData.Substring(result.ResponseData.IndexOf("access_token"));
                String[] keyValPairs = responseData.Split('&');
                string access_token = null;
                string expires_in = null;
                for (int i = 0; i < keyValPairs.Length; i++)
                {
                    String[] splits = keyValPairs[i].Split('=');
                    switch (splits[0])
                    {
                        case "access_token":
                            access_token = splits[1]; //you may want to store access_token for further use. Look at Scenario5 (Account Management).
                            break;
                        case "expires_in":
                            expires_in = splits[1];
                            break;
                    }
                }

                AppCallbacks.Instance.UnityActivate(Window.Current.CoreWindow, CoreWindowActivationState.CodeActivated);
                AppCallbacks.Instance.InvokeOnAppThread(() =>
                {
                    // back to Unity
                    //function to call or variable that accepts the access token 
                }, false);
                //OutputToken(result.ResponseData.ToString());
                //await GetFacebookUserNameAsync(result.ResponseData.ToString());
            }
            else if (result.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
            {
                //OutputToken("HTTP Error returned by AuthenticateAsync() : " + result.ResponseErrorDetail.ToString());
                AppCallbacks.Instance.InvokeOnAppThread(() =>
                {
                    // back to Unity
                    //function to call indicating something went wrong
                }, false);
            }
            else if(result.ResponseStatus == WebAuthenticationStatus.UserCancel)
            {
                //OutputToken("Error returned by AuthenticateAsync() : " + result.ResponseStatus.ToString());
                AppCallbacks.Instance.InvokeOnAppThread(() =>
                {
                    // back to Unity
                    //function to call indicating something went wrong
                }, false);
            }

        }
#endif

        /// <summary>
        /// Invoked when application is launched via file
        /// Read more - http://msdn.microsoft.com/library/windows/apps/br224742
        /// </summary>
        /// <param name="args"></param>
        protected override void OnFileActivated(FileActivatedEventArgs args)
        {
            string appArgs = "";
            Windows.ApplicationModel.Activation.SplashScreen splashScreen = null;

            splashScreen = args.SplashScreen;
            appArgs += "File=";
            bool firstFileAdded = false;
            foreach (var file in args.Files)
            {
                if (firstFileAdded) appArgs += ";";
                appArgs += file.Path;
                firstFileAdded = true;
            }

            InitializeUnity(appArgs, splashScreen);
        }

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used when the application is launched to open a specific file, to display
        /// search results, and so forth.
        /// </summary>
        /// <param name="args">Details about the launch request and process.</param>
        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            InitializeUnity(args.Arguments, args.SplashScreen);
        }

        private void InitializeUnity(string args, Windows.ApplicationModel.Activation.SplashScreen splashScreen)
        {
#if UNITY_WP_8_1
            ApplicationView.GetForCurrentView().SuppressSystemOverlays = true;
#pragma warning disable 4014
            StatusBar.GetForCurrentView().HideAsync();
#pragma warning restore 4014
#endif

            appCallbacks.SetAppArguments(args);
            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null && !appCallbacks.IsInitialized())
            {
                var mainPage = new MainPage(splashScreen);
                Window.Current.Content = mainPage;
                Window.Current.Activate();

                // Setup scripting bridge
                _bridge = new WinRTBridge.WinRTBridge();
                appCallbacks.SetBridge(_bridge);

#if !UNITY_WP_8_1
                appCallbacks.SetKeyboardTriggerControl(mainPage);
#endif

                appCallbacks.SetSwapChainPanel(mainPage.GetSwapChainPanel());
                appCallbacks.SetCoreWindowEvents(Window.Current.CoreWindow);
                appCallbacks.InitializeD3DXAML();
            }

            Window.Current.Activate();

#if UNITY_WP_8_1
            SetupLocationService();
#endif
        }

        private void RemoveSplashScreen()
        {
            // This will fail if you change main window class
            // Make sure to adjust accordingly if you do something like this
            MainPage page = (MainPage)Window.Current.Content;
            page.RemoveSplashScreen();
        }

#if UNITY_WP_8_1
        // This is the default setup to show location consent message box to the user
        // You can customize it to your needs, but do not remove it completely if your application
        // uses location services, as it is a requirement in Windows Store certification process
        private async void SetupLocationService()
        {
            if (!appCallbacks.IsLocationCapabilitySet())
            {
                return;
            }

            const string settingName = "LocationContent";
            bool userGaveConsent = false;

            object consent;
            var settings = Windows.Storage.ApplicationData.Current.LocalSettings;
            var userWasAskedBefore = settings.Values.TryGetValue(settingName, out consent);

            if (!userWasAskedBefore)
            {
                var messageDialog = new Windows.UI.Popups.MessageDialog("Can this application use your location?", "Location services");

                var acceptCommand = new Windows.UI.Popups.UICommand("Yes");
                var declineCommand = new Windows.UI.Popups.UICommand("No");

                messageDialog.Commands.Add(acceptCommand);
                messageDialog.Commands.Add(declineCommand);

                userGaveConsent = (await messageDialog.ShowAsync()) == acceptCommand;
                settings.Values.Add(settingName, userGaveConsent);
            }
            else
            {
                userGaveConsent = (bool)consent;
            }

            if (userGaveConsent)
            {   // Must be called from UI thread
                appCallbacks.SetupGeolocator();
            }
        }
#endif
        /// <summary>
        /// Invoked when Navigation to a certain page fails
        /// </summary>
        /// <param name="sender">The Frame which failed navigation</param>
        /// <param name="e">Details about the navigation failure</param>
        void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
        }

        /// <summary>
        /// Invoked when application execution is being suspended.  Application state is saved
        /// without knowing whether the application will be terminated or resumed with the contents
        /// of memory still intact.
        /// </summary>
        /// <param name="sender">The source of the suspend request.</param>
        /// <param name="e">Details about the suspend request.</param>
        private async void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            await SuspensionManager.SaveAsync();
            deferral.Complete();
        }
    }
}

您还需要ContinuationManager.cs类和SuspensionManager.cs类,但主要用于WP8.1 Universal。这不是W8.1所必需的,所以你应该确保使用#defines将它们保存在自己的上下文中

如果您愿意,可以直接在Facebook应用程序上调用,而不是调用WebAuthenticationBroker,但我不知道所有细节。您可以在Facebook的网站developers.facebook.com/docs/facebook-login/login-for-windows-phone上阅读。如果用户没有安装该方法,则不建议使用该方法。

Long(匆忙)故事简短,调用WebAuthenticationBroker,处理OnActivated事件中的continuation事件以捕获WebAuthenticationBrokerContinuationEventArgs对象,并使用您认为合适的数据。如果要调用统一端的任何代码,请务必使用以下内容。请注意,您可以直接从App.xaml.cs访问c#代码: -

AppCallbacks.Instance.InvokeOnAppThread(() =>
                {
                    // back to Unity
                    //your code here
                }, false);

另请注意,这主要是为了获取访问令牌。一旦我们有了这个,我们可以直接向facebook发送基本的WWW调用并从中获取数据。数据将以JSON格式返回(ps这是一种非常棒的干净格式!)您可以使用.NET json库将其序列化为类。我使用json2csharp.com将任何示例输出转换为我刚刚解析到json库中的类。