Skip to content

Instantly share code, notes, and snippets.

@hon454
Created November 27, 2017 16:38
Show Gist options
  • Save hon454/3ae400b2943ee01043de55804aaf005f to your computer and use it in GitHub Desktop.
Save hon454/3ae400b2943ee01043de55804aaf005f to your computer and use it in GitHub Desktop.
Android VR Webview Texture for Unity (more information at: https://jerome.gangneux.net/projects/2017-02-android-vr-webview/)
using UnityEngine;
using UnityEngine.EventSystems;
using System;
using System.Collections;
using System.Runtime.InteropServices;
[RequireComponent(typeof(Renderer))]
public class AndroidWebview : MonoBehaviour, IPointerExitHandler, IPointerClickHandler, IBeginDragHandler, IDragHandler, IEndDragHandler {
// Public values
/**
* Default URL to load, you can load a new URL with LoadUrl(String url)
*/
public string url = "https://www.google.com/";
/**
* Default Texture size
*/
public int textureWidth = 640;
public int textureHeight = 640;
/**
* This is only to show that delegation and events works
* You can remove this :)
*/
public TextMesh statusText = null;
public TextMesh eventText = null;
/**
* Get more debug message in the Android logcat
*/
public bool isDebug = false;
// Internals objects
protected Texture2D nativeTexture = null;
protected IntPtr nativeTexId = IntPtr.Zero;
protected AndroidJavaObject view = null;
/**
* You need a Renderer with a texture (best result with unlit texture)
*/
protected Renderer mainRenderer = null;
public enum ActionEvent {
Down = 1,
Up = 2,
Move = 3,
Max
}
protected enum SurfaceEvent {
Init = 0,
Stop = 1,
Update = 2,
Max
};
// Configuration
/**
* Set to true if you want to send event to the Native Webview
* Related to PositionInformation(Vector2, ActionEvent)
*/
protected bool propagateHitEvent = true;
// State
protected bool isClickedDown = false;
protected bool isScrolling = false;
protected Vector2 lastPosition = Vector2.zero;
// Unity life cycle
/**
* Used to configure the renderer and the external texture
*/
void Awake () {
JRMGX_Android_View_Init ();
mainRenderer = GetComponent<Renderer> ();
if (mainRenderer.material == null) {
Debug.LogError ("No material for surface");
} else if (mainRenderer.material.mainTexture == null) {
Debug.LogError ("No material.mainTexture for surface");
}
nativeTexture = Texture2D.CreateExternalTexture (textureWidth, textureHeight, TextureFormat.RGBA32, true, false, IntPtr.Zero);
IssuePluginEvent (SurfaceEvent.Init);
}
/**
* Start the rendering of the Webview
*/
void Start() {
StartCoroutine (DelayedStart());
}
/**
* Check each frame if the Webview has a new update
*/
void Update () {
IntPtr currTexId = JRMGX_Android_View_GetTexture ();
if (currTexId != nativeTexId) {
nativeTexId = currTexId;
nativeTexture.UpdateExternalTexture (currTexId);
Debug.Log ("AndroidView - texture size is " + nativeTexture.width + " x " + nativeTexture.height);
}
IssuePluginEvent (SurfaceEvent.Update);
}
/**
* Ask the Webview to consume waiting event
*/
void LateUpdate () {
if (propagateHitEvent == false) return;
if (view != null) {
view.Call ("eventPoll");
}
}
void OnApplicationQuit () {
IssuePluginEvent (SurfaceEvent.Stop);
}
// Public interface
/**
* Webview method goBack
* Load the previous page if possible
*/
public void GoBack () {
view.Call ("goBack");
}
/**
* Webview method goForward
* Load the next page if possible
*/
public void GoForward () {
view.Call ("goForward");
}
/**
* Webview method loadUrl
* Load a new Url in the webview
*/
public void LoadUrl (String newUrl) {
url = newUrl;
view.Call ("loadUrl", newUrl);
}
// Delegation
/**
* The Webview will give you delegate messages for specific events
* message:
* - onPageStarted:string <-- when a new url is about to be loaded
* - onPageFinished:string <-- when a new url has finished to load
* - onReceivedError:string <-- when an error happen
* you need to parse these messages and handle it as you wish
*/
protected void Delegation (string message) {
// Do something here with `message`
if (statusText != null) {
statusText.text = message;
}
}
/**
* Debug method, can be removed
*/
protected void PrintEvent (string message) {
if (eventText == null) return;
eventText.text = message;
}
// Sending event
/**
* This is how you can send `Move` action to the Webview
* position is the final pointer position on the underlying 2D Webview
* It is android coordinate system: top,left = 0,0 / bottom,right = textureHeight,textureWidth
* See the `Event system` section below for an example
*/
public void PositionInformation (Vector2 position, ActionEvent actionType) {
if (propagateHitEvent == false) return;
if (view != null) {
// This is for debugging only you should remove it
PrintEvent ("event " + actionType.ToString () + " sent: " + position.ToString ());
view.Call ("eventAdd", (int) position.x, (int) position.y, (int) actionType);
}
}
// Event system
/**
* Convert an Unity `PointerEventData` position to the webview coordinate position
* This needs to be adapted for you scene
*/
public void UpdateLastPosition (PointerEventData eventData) {
// This needs to be adapted for you scene
// It depends on how you transformed your GameObject
// You will have try to adapt +/- and choose from x/y/z on position
Vector3 position = transform.InverseTransformPoint (eventData.pointerCurrentRaycast.worldPosition);
//Debug.Log (position); // Use debug.log and adb logcat to find out
float x = ((position.x + 5) / 10) * textureWidth;
float y = ((position.z - 5) / -10) * textureHeight;
lastPosition = new Vector2 (x, y);
}
#region IPointerExitHandler implementation
/**
* When the pointer get out of the GameObject we considerate that the user did an ActionEvent.Up
*/
public void OnPointerExit (PointerEventData eventData) {
isClickedDown = false;
UpdateLastPosition (eventData);
PositionInformation (lastPosition, ActionEvent.Up);
}
#endregion
#region IPointerClickHandler implementation
/**
* Example of event system implementation
*/
public void OnPointerClick (PointerEventData eventData) {
if (isScrolling) return; // Skip the click event if we are scrolling
UpdateLastPosition (eventData);
PositionInformation (lastPosition, ActionEvent.Down);
PositionInformation (lastPosition, ActionEvent.Up);
}
#endregion
#region IEndDragHandler implementation
public void OnEndDrag (PointerEventData eventData) {
UpdateLastPosition (eventData);
PositionInformation (lastPosition, ActionEvent.Up);
isScrolling = false;
}
#endregion
#region IDragHandler implementation
public void OnDrag (PointerEventData eventData) {
isScrolling = true;
UpdateLastPosition (eventData);
PositionInformation (lastPosition, ActionEvent.Move);
}
#endregion
#region IBeginDragHandler implementation
public void OnBeginDrag (PointerEventData eventData) {
isScrolling = true;
UpdateLastPosition (eventData);
PositionInformation (lastPosition, ActionEvent.Down);
}
#endregion
#region IGvrPointerHoverHandler implementation
/**
* Example of event system implementation for Google Daydream
* This will conflict with Unity event handle above, please remove them.
*
* This method is an example and works only with the Google Daydream asset installed (IGvrPointerHoverHandler)
* if you don't use Google Daydream you may achieve the same result with classic Unity event handler (above)
*/
public void OnGvrPointerHover (PointerEventData eventData) {
/*
UpdateLastPosition (eventData);
// If you use the Google Daydream asset, you could do something like that
if (GvrController.ClickButtonDown) {
isClickedDown = true;
PositionInformation (lastPosition, ActionEvent.Down);
}
else if (GvrController.ClickButtonUp) {
isClickedDown = false;
PositionInformation (lastPosition, ActionEvent.Up);
}
if (isClickedDown) {
PositionInformation (lastPosition, ActionEvent.Move);
}
*/
}
#endregion
// Internal to plugin
// ...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment