Uniwebview2插件常见问题以及刘海屏屏幕适配,屏幕旋转的解决方案

  • Post author:
  • Post category:其他




uniwebview2



是什么

​ uniwebview2是一个在Android和IOS移动端平台下的Unity内置浏览器插件。主要是用来在游戏界面的最上面显示运营开发的web活动或者论坛等网页。



为什么

​ Unity自带了一个打开网址url的函数接口

Application.OpenURL(url);

不过该接口会调用手机自带的浏览器来打开该网页,但是玩家想要返回游戏就比较困难,还需要重新去找对应的游戏App,因此需要一个插件能够内置在游戏中,在游戏内打开浏览器,方便关闭网页之后接着运行游戏。



怎么做

​ 将下载好的uniwebview2的插件包导入unity之后,主要看UniWebView.cs这个文件,所有和网页相关的前进,后退,刷新,返回,屏幕旋转适配都是在这个文件中。我们需要将其封装成一个外部可以直接调用的接口来使用。


打开网页接口

SDK.UniWebViewManager.Instance.OpenUrl(Url, CallBack);

一共需要两个参数,一个是string类型的url(需要打开的网址要有http或者https开头的)和System.Action类型的回调函数(用于在网页关闭的时候调用)


关闭网页接口

SDK.UniWebViewManager.Instance.DoCloseAll(); 


网页前进接口

SDK.UniWebViewManager.Instance.GoForward();


网页后退接口

SDK.UniWebViewManager.Instance.GoBack();


网页刷新接口

SDK.UniWebViewManager.Instance.Reload();



Q&A


Q1:在打开游戏内的uniwebview2情况下,将游戏App切到后台导致失去焦点,重新进入游戏的时候游戏无法响应

A1: 在游戏暂停的时候将网页给隐藏,当游戏切回来的时候重新调用显示即可。打开UniWebView.cs文件添加如下代码

 	/// <summary>
    /// 添加UniWebView插件退到后台导致的失去焦点问题;
    /// </summary>
    /// <param name="pauseStatus"></param>
    private void OnApplicationPause(bool pauseStatus)
    {
#if UNITY_IOS || UNITY_ANDROID
        if (pauseStatus)
        {
            Hide();
        }
        else
        {
            Show();
        }
#endif
    }


Q2:手指快速点击按钮的情况下会导致多次调用,导致打开了多个网页

A2: 修改内置浏览器调用方式为在界面打开的时候才调用SDK接口,这样就避免双击的时候多次调用导致的打开多个网页。我们新建一个Panel界面,在点击按钮的时候先打开界面,然后再界面的Open和Close的时候调用网页的打开和关闭接口。PanelUniWebViewController就是内置浏览器的通用打开界面。

	//做一些打开界面时的处理.;
    protected override void OnPanelOpen()
    {
        if (data == null)
        {
            LogHelper.LogError("内置浏览器插件的传入数据为空;");
            return;
        }
        //界面打开的时候调用内置浏览器SDK的接口,避免多次调用会导致打开多个网页的问题;
        SDK.UniWebViewManager.Instance.OpenUrl(data.Url, data.CallBack);
    }
 	//关闭按钮的回调函数
    private void OnClickCloseEvt()
    {
        // 关闭所有的网页;
        DNA.SDK.UniWebViewManager.Instance.DoCloseAll();
    }


Q3:uniwebview2浏览器打开的都是全屏的网页,我们需要定制浏览器的显示区域要怎么办?比如如何适配刘海屏

A3:UniWebView2有一个屏幕旋转变化的时候回调函数,我们只需要监听并做相应的适配即可。

webView.InsetsForScreenOreitation += InsetsForScreenOreitation;

我们在对应的InsetsForScreenOreitation监听函数里面添加代码

		// This method will be called when the screen orientation changed. Here we return UniWebViewEdgeInsets(5,5,5,5)
        // for both situation, which means the inset is 5 point for iOS and 5 pixels for Android from all edges.
        // Note: UniWebView is using point instead of pixel in iOS. However, the `Screen.width` and `Screen.height` will give you a
        // pixel-based value. 
        // You could get a point-based screen size by using the helper methods: `UniWebViewHelper.screenHeight` and `UniWebViewHelper.screenWidth` for iOS.
        UniWebViewEdgeInsets InsetsForScreenOreitation(UniWebView webView, UniWebViewOrientation orientation)
        {

#if UNI_WEB_VIEW
#if UNITY_IOS || UNITY_ANDROID || UNITY_WP8
          
        //SCREEN_WIDTH = 1136;
        //SCREEN_HEIGHT = 640;
        LogHelper.Log("InsetsForScreenOreitation orientation " + orientation);
        // int aTop, int aLeft, int aBottom, int aRight;
        // 横屏;
        if (orientation == UniWebViewOrientation.LandScape)
        {
            aTop = 0;
            aLeft = 88;
            aBottom = 88;
            aRight = 88;
            // 适配多分辨率的情况;
            // 1136  => 88;
            // Width => Width/1136*88;
            aLeft = (aLeft * UniWebViewHelper.screenWidth) / SCREEN_WIDTH;
            aRight = (aRight * UniWebViewHelper.screenWidth) / SCREEN_WIDTH;
            aBottom = (aBottom * UniWebViewHelper.screenHeight) / SCREEN_HEIGHT;
            //用于测试不同手机的适配问题
            LogHelper.Log(StringUtil.Format("UniWeb aTop = {0}, aLeft = {1}, aBottom = {2}, aRight = {3}", aTop, aLeft, aBottom, aRight));             
            EventMsgCenter.SendMsg(EEventName.Url_UpdateSize);
            return new UniWebViewEdgeInsets(aTop, aLeft, aBottom, aRight);
        }
        else
        {
            aTop = 0;
            aLeft = 0;
            aBottom = 88;
            aRight = 0;
            // 竖屏;
            aBottom = (aBottom * UniWebViewHelper.screenHeight) / SCREEN_HEIGHT;

            //用于测试不同手机的适配问题
            LogHelper.Log(StringUtil.Format("UniWeb aTop = {0}, aLeft = {1}, aBottom = {2}, aRight = {3}", aTop, aLeft, aBottom, aRight));             
            EventMsgCenter.SendMsg(EEventName.Url_UpdateSize);
            return new UniWebViewEdgeInsets(aTop, aLeft, aBottom, aRight);
        }
#endif
#endif
            return null;
        }

UniWebViewEdgeInsets函数接口是用来返回浏览器的显示区域,里面是4个参数,分别是

  1. int aTop //距离屏幕顶部的像素距离
  2. int aLeft //距离屏幕左边的像素距离
  3. int aBottom //距离屏幕底部的像素距离
  4. int aRight //距离屏幕右边的像素距离
	/// <summary>
    /// Initializes a new instance of the <see cref="UniWebViewEdgeInsets"/> class.
    /// </summary>
    /// <param name="aTop">Top inset by point.</param>
    /// <param name="aLeft">Left inset by point.</param>
    /// <param name="aBottom">Bottominset by point.</param>
    /// <param name="aRight">Rightinset by point.</param>
    public UniWebViewEdgeInsets(int aTop, int aLeft, int aBottom, int aRight) {
        top = aTop;
        left = aLeft;
        bottom = aBottom;
        right = aRight;
    }

既然是像素距离,那么我们就需要根据手机屏幕来重新计算,将对应的像素传入进去,游戏中是按照1136*640来做的,所以当我们在1136下,距离左边是88像素的时候,在其他分辨率下像素点计算如下:

aLeft = 88;
// 适配多分辨率的情况;
// 1136  => 88;
// Width => Width/1136*88;
aLeft = (aLeft * UniWebViewHelper.screenWidth) / SCREEN_WIDTH;

同样的在640下,距离底部88像素的时候,在其他分辨率下像素点计算如下:

aBottom = 88;
// 适配多分辨率的情况;
// 640  => 88;
// Height => Height/640*88;
aBottom = (aBottom * UniWebViewHelper.screenHeight) / SCREEN_HEIGHT;

在这里插入图片描述

由于刘海屏在Iphone下面的有个bar条的,所以这里的按钮都设置在底部的背景框偏上的位置。

返回按钮在下面有个取巧的好处就是,不用去适配刘海的问题,因为刘海都是在手机横屏时候的左右位置(手机竖屏时候的上下位置)。(PS:玩王者荣耀的时候看到他们的活动页面的按钮布局想到的启示,所以没事的时候多玩玩其他游戏还是很有好处的hhhh)


Q4:uniwebview2浏览器插件在IPhone下需要支持旋转查看,就是在手机方向按键没有锁定的情况下,可以横屏看也可以竖屏看,当退出浏览模式返回进入游戏的时候,还是按照之前的横屏显示,这个要怎么做?

A4:提这个问题是因为运营那边设计网页的时候内容显示不下需要在竖屏的情况下面显示。这个时候我们需要根据玩家操作,在打开网页的时候让屏幕可以支持旋转,在关闭的时候只能横向旋转。 新建一个屏幕管理类ScreenManager,里面只需要两个函数,一个用来打开网页的时候屏幕的控制,一个是关闭网页的时候使用。

//Unity 屏幕管理类

using DNA;
using UnityEngine;
#if UNITY_IOS || UNITY_IPHONE
using System.Runtime.InteropServices;
#endif
public class ScreenManager : ReleaseSingleton<ScreenManager>
{
    /// <summary>
    /// Url打开的时候设置横屏/竖屏,允许自动旋转屏幕
    /// </summary>
    public void OnUrlOpen()
    {
#if UNITY_IPHONE || UNITY_IOS
        DNA_U3D_SetPortrait();
#endif
        temp = Screen.orientation;
        Screen.orientation = ScreenOrientation.AutoRotation;
        Screen.autorotateToLandscapeRight = true;
        Screen.autorotateToLandscapeLeft = true;
        Screen.autorotateToPortraitUpsideDown = false;
        Screen.autorotateToPortrait = true;
    }
    ScreenOrientation temp;
    /// <summary>
    /// Url关闭的时候设置回横屏显示
    /// </summary>
    public void OnUrlClose()
    {
        //IOS水平方向都可以
#if UNITY_IPHONE || UNITY_IOS
        DNA_U3D_SetLandscape();
        Screen.orientation = temp;
        Screen.autorotateToLandscapeRight = true;
        Screen.autorotateToLandscapeLeft = true;
        Screen.autorotateToPortraitUpsideDown = false;
        Screen.autorotateToPortrait = false;
        Screen.orientation = ScreenOrientation.AutoRotation;

#elif UNITY_ANDROID
        //安卓锁住方向
        Screen.orientation = ScreenOrientation.LandscapeLeft;
        Screen.autorotateToLandscapeLeft = true;
#endif
    }

#if UNITY_IPHONE || UNITY_IOS
    [DllImport("__Internal")]
    private static extern void DNA_U3D_SetLandscape();
    [DllImport("__Internal")]
    private static extern void DNA_U3D_SetPortrait();
#endif
}

IOS下需要增加两个文件ScreenManager .h和ScreenManager .mm文件

#ifndef ScreenManager_h
#define ScreenManager_h

#import <Foundation/Foundation.h>

#ifdef __cplusplus
extern "C"
{
#endif
    void DNA_U3D_SetLandscape();
    void DNA_U3D_SetPortrait();
#ifdef __cplusplus
}
#endif

@interface ScreenManager : NSObject
@property (nonatomic, assign) BOOL isPortrait;

- (ScreenManager *)sharedInstance;

- (bool) DNA_U3D_GetPortrait;

@end

#endif /* ScreenManager_h */

mm文件如下

#import "ScreenManager.h"
#import <UIKit/UIKit.h>

@interface ScreenManager () <NSObject>

@end


static ScreenManager* instance = nil;
@implementation ScreenManager
+ (ScreenManager *)sharedInstance;
{
    @synchronized (self) {
        if(instance==nil)
        {
            instance = [[self alloc] init];
        }
    }
    return instance;
}

-(bool) DNA_U3D_GetPortrait
{
    return self.isPortrait;
}

@end

#if defined (__cplusplus)
extern "C"
{
#endif
void DNA_U3D_SetLandscape()
{
    NSLog(@"设置水平方向");
    [[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIInterfaceOrientationLandscapeRight] forKey:@"orientation"];    
    [ScreenManager sharedInstance] .isPortrait = false;
}

void DNA_U3D_SetPortrait()
{
    NSLog(@"设置垂直方向");
    [ScreenManager sharedInstance] .isPortrait = true;
}
#if defined (__cplusplus)
}
#endif

在“UnityAppController.mm”文件中添加头文件引用

#include "Screen/ScreenManager.h"

同时在- (NSUInteger)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window函数中修改代码如下:

- (NSUInteger)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window
  { 
  	bool isPortrait = [[ScreenManager sharedInstance] DNA_U3D_GetPortrait];
    if(isPortrait)
        return UIInterfaceOrientationMaskAllButUpsideDown;
    return UIInterfaceOrientationMaskLandscape;
  }

该函数在手机屏幕方向变化的时候会调用到。


注意:如果我们在手机旋转到竖屏的时候退出uniwebview2,这个时候是竖屏,返回游戏的时候,这个时候屏幕并没有变化,所以supportedInterfaceOrientationsForWindow这个函数是不会被调用到的,当返回游戏的时候,屏幕还是竖屏,必须需要手动旋转一下才能恢复横屏模式。所以我们需要在返回游戏的时候强制设置一下手机为横屏,代码如下

void DNA_U3D_SetLandscape()
{
    NSLog(@"设置水平方向");
    [[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIInterfaceOrientationLandscapeRight] forKey:@"orientation"];    
    [ScreenManager sharedInstance] .isPortrait = false;
}



版权声明:本文为onelei1994原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。