Windows phone 8 和 Unity 5 支持 Facebook SDK

Windows phone 8 and Unity 5 support for Facebook SDK

这是对 Facebook SDK 支持 WP8 和 Unity 5 的请求。 我是一名开发人员,想要制作跨多个平台的游戏,并且能够将游戏发布到 Windows Phone 8 商店是我议程的重要组成部分。

是否计划很快发布对该平台的支持?如果是这样,您打算什么时候发布它?

此外,是否即将发布专为 Unity 5 设计的 Unity SDK?我已经设法让当前版本正常工作,但由于它尚未得到完全支持,我不知道什么可以,什么不能。

如能提供有关这些问题的任何信息,我们将不胜感激!

更新:我运行进入了这个解释"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

请注意我如何将 WebAuthenticationBroker.AuthenticateAndContinue 用于 windows phone 和 WebAuthenticationBroker.AuthenticateAsync 用于 windows 8. 这对于它们各自的平台是必需的。您可能想要研究获取 WebAuthenticationBroker,它是一个适用于 WP8 和 WSA 的 Microsoft class(我猜您的目标是 WSA,我也是):-

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

您还需要统一构建一个 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 class 和 SuspensionManager.cs class 但主要用于 WP8.1 Universal。这对于 W8.1 是不需要的,因此您应该确保您使用#defines 将它们保持在它们自己的上下文中

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

长话短说,调用 WebAuthenticationBroker,处理 OnActivated 事件中的延续事件以捕获通过的 WebAuthenticationBrokerContinuationEventArgs 对象并使用您认为合适的数据。如果您想在统一端调用任何代码,请务必使用以下内容。请注意,您可以直接从 App.xaml.cs:-

访问 c# 代码
AppCallbacks.Instance.InvokeOnAppThread(() =>
                {
                    // back to Unity
                    //your code here
                }, false);

还要注意,这里主要是为了获取access token。一旦我们有了它,我们就可以直接向 facebook 进行基本的 WWW 调用并从中获取数据。数据将以 JSON 格式返回(ps 这是一种非常干净的格式!)您可以使用 .NET json 库将其序列化为 class .我使用 json2csharp.com 将任何示例输出转换为 class,我只是将其解析到 json 库中。