parent
ea4175c67a
commit
bb91cb4c78
|
|
@ -3,10 +3,10 @@ using UnityEngine;
|
|||
// Test
|
||||
public class WebController : MonoBehaviour
|
||||
{
|
||||
//UniWebView webView;
|
||||
UniWebView webView;
|
||||
|
||||
void Start()
|
||||
{/*
|
||||
{
|
||||
DontDestroyOnLoad(this);
|
||||
// Create a game object to hold UniWebView and add component.
|
||||
var webViewGameObject = new GameObject("UniWebView");
|
||||
|
|
@ -58,15 +58,15 @@ public class WebController : MonoBehaviour
|
|||
Destroy(webView);
|
||||
webView = null;
|
||||
}
|
||||
};*/
|
||||
};
|
||||
}
|
||||
|
||||
void Restart()
|
||||
{
|
||||
/*if (webView != null)
|
||||
if (webView != null)
|
||||
{
|
||||
webView.Reload();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
dependencies {
|
||||
implementation project(':unityLibrary')
|
||||
}
|
||||
|
||||
android {
|
||||
namespace "**NAMESPACE**"
|
||||
ndkPath "**NDKPATH**"
|
||||
|
||||
compileSdkVersion **APIVERSION**
|
||||
buildToolsVersion '**BUILDTOOLS**'
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion **MINSDKVERSION**
|
||||
targetSdkVersion **TARGETSDKVERSION**
|
||||
applicationId '**APPLICATIONID**'
|
||||
ndk {
|
||||
abiFilters **ABIFILTERS**
|
||||
}
|
||||
versionCode **VERSIONCODE**
|
||||
versionName '**VERSIONNAME**'
|
||||
}
|
||||
|
||||
aaptOptions {
|
||||
noCompress = **BUILTIN_NOCOMPRESS** + unityStreamingAssets.tokenize(', ')
|
||||
ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~"
|
||||
}**SIGN**
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
minifyEnabled **MINIFY_DEBUG**
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt')**SIGNCONFIG**
|
||||
jniDebuggable true
|
||||
}
|
||||
release {
|
||||
minifyEnabled **MINIFY_RELEASE**
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt')**SIGNCONFIG**
|
||||
}
|
||||
}**PACKAGING_OPTIONS****PLAY_ASSET_PACKS****SPLITS**
|
||||
**BUILT_APK_LOCATION**
|
||||
bundle {
|
||||
language {
|
||||
enableSplit = false
|
||||
}
|
||||
density {
|
||||
enableSplit = false
|
||||
}
|
||||
abi {
|
||||
enableSplit = true
|
||||
}
|
||||
}
|
||||
}**SPLITS_VERSION_CODE****LAUNCHER_SOURCE_BUILD_SETUP**
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
apply plugin: 'com.android.library'
|
||||
**APPLY_PLUGINS**
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
**DEPS**}
|
||||
|
||||
android {
|
||||
namespace "com.unity3d.player"
|
||||
ndkPath "**NDKPATH**"
|
||||
compileSdkVersion **APIVERSION**
|
||||
buildToolsVersion '**BUILDTOOLS**'
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion **MINSDKVERSION**
|
||||
targetSdkVersion **TARGETSDKVERSION**
|
||||
ndk {
|
||||
abiFilters **ABIFILTERS**
|
||||
}
|
||||
versionCode **VERSIONCODE**
|
||||
versionName '**VERSIONNAME**'
|
||||
consumerProguardFiles 'proguard-unity.txt'**USER_PROGUARD**
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
aaptOptions {
|
||||
noCompress = **BUILTIN_NOCOMPRESS** + unityStreamingAssets.tokenize(', ')
|
||||
ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~"
|
||||
}**PACKAGING_OPTIONS**
|
||||
}
|
||||
**IL_CPP_BUILD_SETUP**
|
||||
**SOURCE_BUILD_SETUP**
|
||||
**EXTERNAL_SOURCES**
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 92454175c62504ab5bf7128917b56362
|
||||
folderAsset: yes
|
||||
timeCreated: 1490878496
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f7ee8c3eb642344b08f4ceeb53d70cd1
|
||||
timeCreated: 1497057465
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fd05a3d83a17b3646b6d1fa29a91f6a3
|
||||
guid: 5f0047c1c8c8348de9d66b0496b353e1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
using System.Xml;
|
||||
using System.Text;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
internal class UniWebViewAndroidXmlDocument : XmlDocument {
|
||||
private readonly string path;
|
||||
protected readonly XmlNamespaceManager nameSpaceManager;
|
||||
protected const string AndroidXmlNamespace = "http://schemas.android.com/apk/res/android";
|
||||
|
||||
protected UniWebViewAndroidXmlDocument(string path) {
|
||||
this.path = path;
|
||||
using (var reader = new XmlTextReader(path)) {
|
||||
reader.Read();
|
||||
Load(reader);
|
||||
}
|
||||
nameSpaceManager = new XmlNamespaceManager(NameTable);
|
||||
nameSpaceManager.AddNamespace("android", AndroidXmlNamespace);
|
||||
}
|
||||
|
||||
public void Save() {
|
||||
SaveAs(path);
|
||||
}
|
||||
|
||||
private void SaveAs(string path)
|
||||
{
|
||||
using var writer = new XmlTextWriter(path, new UTF8Encoding(false));
|
||||
writer.Formatting = Formatting.Indented;
|
||||
Save(writer);
|
||||
}
|
||||
}
|
||||
|
||||
internal class UniWebViewAndroidManifest : UniWebViewAndroidXmlDocument {
|
||||
private readonly XmlElement manifestElement;
|
||||
private readonly XmlElement applicationElement;
|
||||
|
||||
public UniWebViewAndroidManifest(string path) : base(path) {
|
||||
manifestElement = SelectSingleNode("/manifest") as XmlElement;
|
||||
applicationElement = SelectSingleNode("/manifest/application") as XmlElement;
|
||||
}
|
||||
|
||||
private XmlAttribute CreateAndroidAttribute(string key, string value) {
|
||||
XmlAttribute attr = CreateAttribute("android", key, AndroidXmlNamespace);
|
||||
attr.Value = value;
|
||||
return attr;
|
||||
}
|
||||
|
||||
internal XmlNode GetActivityWithLaunchIntent() {
|
||||
return
|
||||
SelectSingleNode(
|
||||
"/manifest/application/activity[intent-filter/action/@android:name='android.intent.action.MAIN' and "
|
||||
+ "intent-filter/category/@android:name='android.intent.category.LAUNCHER']",
|
||||
nameSpaceManager);
|
||||
}
|
||||
|
||||
internal bool SetUsesCleartextTraffic() {
|
||||
var changed = false;
|
||||
if (applicationElement.GetAttribute("usesCleartextTraffic", AndroidXmlNamespace) != "true") {
|
||||
applicationElement.SetAttribute("usesCleartextTraffic", AndroidXmlNamespace, "true");
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
internal bool SetHardwareAccelerated() {
|
||||
var changed = false;
|
||||
var activity = GetActivityWithLaunchIntent() as XmlElement;
|
||||
if (activity == null)
|
||||
{
|
||||
Debug.LogError(
|
||||
"There is no launch intent activity in the AndroidManifest.xml." +
|
||||
" Please check your AndroidManifest.xml file and make sure it has a main activity with intent filter");
|
||||
return false;
|
||||
}
|
||||
if (activity.GetAttribute("hardwareAccelerated", AndroidXmlNamespace) != "true") {
|
||||
activity.SetAttribute("hardwareAccelerated", AndroidXmlNamespace, "true");
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
internal bool AddCameraPermission() {
|
||||
var changed = false;
|
||||
var cameraPermission = "/manifest/uses-permission[@android:name='android.permission.CAMERA']";
|
||||
var cameraPermissionNode = SelectNodes(cameraPermission, nameSpaceManager);
|
||||
if (cameraPermissionNode == null || cameraPermissionNode.Count == 0) {
|
||||
var elem = CreateElement("uses-permission");
|
||||
elem.Attributes.Append(CreateAndroidAttribute("name", "android.permission.CAMERA"));
|
||||
manifestElement.AppendChild(elem);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
var hardwareCamera = "/manifest/uses-feature[@android:name='android.hardware.camera']";
|
||||
var hardwareCameraNode = SelectNodes(hardwareCamera, nameSpaceManager);
|
||||
if (hardwareCameraNode == null || hardwareCameraNode.Count == 0) {
|
||||
var elem = CreateElement("uses-feature");
|
||||
elem.Attributes.Append(CreateAndroidAttribute("name", "android.hardware.camera"));
|
||||
manifestElement.AppendChild(elem);
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
internal bool AddMicrophonePermission() {
|
||||
bool changed = false;
|
||||
var microphonePermission = "/manifest/uses-permission[@android:name='android.permission.MICROPHONE']";
|
||||
var microphonePermissionNode = SelectNodes(microphonePermission, nameSpaceManager);
|
||||
if (microphonePermissionNode == null || microphonePermissionNode.Count == 0) {
|
||||
var elem = CreateElement("uses-permission");
|
||||
elem.Attributes.Append(CreateAndroidAttribute("name", "android.permission.MICROPHONE"));
|
||||
manifestElement.AppendChild(elem);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
var microphoneHardware = "/manifest/uses-feature[@android:name='android.hardware.microphone']";
|
||||
var microphoneHardwareNode = SelectNodes(microphoneHardware, nameSpaceManager);
|
||||
if (microphoneHardwareNode == null || microphoneHardwareNode.Count == 0) {
|
||||
var elem = CreateElement("uses-feature");
|
||||
elem.Attributes.Append(CreateAndroidAttribute("name", "android.hardware.microphone"));
|
||||
manifestElement.AppendChild(elem);
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
internal bool AddReadExternalStoragePermission() {
|
||||
var changed = false;
|
||||
var externalPermission = "/manifest/uses-permission[@android:name='android.permission.READ_EXTERNAL_STORAGE']";
|
||||
var externalNode = SelectNodes(externalPermission, nameSpaceManager);
|
||||
if (externalNode == null || externalNode.Count == 0) {
|
||||
var elem = CreateElement("uses-permission");
|
||||
elem.Attributes.Append(CreateAndroidAttribute("name", "android.permission.READ_EXTERNAL_STORAGE"));
|
||||
manifestElement.AppendChild(elem);
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
internal bool AddWriteExternalStoragePermission() {
|
||||
var changed = false;
|
||||
var externalPermission = "/manifest/uses-permission[@android:name='android.permission.WRITE_EXTERNAL_STORAGE']";
|
||||
var externalNode = SelectNodes(externalPermission, nameSpaceManager);
|
||||
if (externalNode == null || externalNode.Count == 0) {
|
||||
var elem = CreateElement("uses-permission");
|
||||
elem.Attributes.Append(CreateAndroidAttribute("name", "android.permission.WRITE_EXTERNAL_STORAGE"));
|
||||
manifestElement.AppendChild(elem);
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
internal bool AddAccessFineLocationPermission() {
|
||||
var changed = false;
|
||||
var locationPermission = "/manifest/uses-permission[@android:name='android.permission.ACCESS_FINE_LOCATION']";
|
||||
var locationNode = SelectNodes(locationPermission, nameSpaceManager);
|
||||
if (locationNode == null || locationNode.Count == 0) {
|
||||
var elem = CreateElement("uses-permission");
|
||||
elem.Attributes.Append(CreateAndroidAttribute("name", "android.permission.ACCESS_FINE_LOCATION"));
|
||||
manifestElement.AppendChild(elem);
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
internal bool AddAuthCallbacksIntentFilter(string[] authCallbackUrls) {
|
||||
var changed = false;
|
||||
XmlElement authActivityNode;
|
||||
if (authCallbackUrls.Length > 0) {
|
||||
var authActivity = "/manifest/application/activity[@android:name='com.onevcat.uniwebview.UniWebViewAuthenticationActivity']";
|
||||
var list = SelectNodes(authActivity, nameSpaceManager);
|
||||
if (list == null || list.Count == 0) {
|
||||
var created = CreateElement("activity");
|
||||
created.SetAttribute("name", AndroidXmlNamespace, "com.onevcat.uniwebview.UniWebViewAuthenticationActivity");
|
||||
created.SetAttribute("exported", AndroidXmlNamespace, "true");
|
||||
created.SetAttribute("launchMode", AndroidXmlNamespace, "singleTask");
|
||||
created.SetAttribute("configChanges", AndroidXmlNamespace, "orientation|screenSize|keyboardHidden");
|
||||
authActivityNode = created;
|
||||
} else {
|
||||
authActivityNode = list[0] as XmlElement;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var url in authCallbackUrls) {
|
||||
var intentFilter = CreateIntentFilter(url);
|
||||
if (intentFilter != null) {
|
||||
authActivityNode?.AppendChild(intentFilter);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (authActivityNode != null) {
|
||||
applicationElement.AppendChild(authActivityNode);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
private XmlElement CreateIntentFilter(string url) {
|
||||
|
||||
var uri = new Uri(url);
|
||||
var scheme = uri.Scheme;
|
||||
if (string.IsNullOrEmpty(scheme)) {
|
||||
Debug.LogError("<UniWebView> Auth callback url contains an empty scheme. Please check the url: " + url);
|
||||
return null;
|
||||
}
|
||||
|
||||
var filter = CreateElement("intent-filter");
|
||||
|
||||
// Check if the scheme is HTTPS
|
||||
// For Android App Links, we need to set the autoVerify attribute to true
|
||||
// This allows Android to automatically verify the association between the app and the website
|
||||
// Note: Only applies to HTTPS URLs, although Android App Links also support HTTP, we do not want it in
|
||||
// UniWebView.
|
||||
// https://developer.android.com/training/app-links
|
||||
if (scheme == "https") {
|
||||
filter.SetAttribute("autoVerify", AndroidXmlNamespace, "true");
|
||||
}
|
||||
|
||||
var action = CreateElement("action");
|
||||
action.SetAttribute("name", AndroidXmlNamespace, "android.intent.action.VIEW");
|
||||
filter.AppendChild(action);
|
||||
|
||||
var defaultCategory = CreateElement("category");
|
||||
defaultCategory.SetAttribute("name", AndroidXmlNamespace, "android.intent.category.DEFAULT");
|
||||
filter.AppendChild(defaultCategory);
|
||||
|
||||
var browseCategory = CreateElement("category");
|
||||
browseCategory.SetAttribute("name", AndroidXmlNamespace, "android.intent.category.BROWSABLE");
|
||||
filter.AppendChild(browseCategory);
|
||||
|
||||
var data = CreateElement("data");
|
||||
data.SetAttribute("scheme", AndroidXmlNamespace, scheme);
|
||||
if (!String.IsNullOrEmpty(uri.Host)) {
|
||||
data.SetAttribute("host", AndroidXmlNamespace, uri.Host);
|
||||
}
|
||||
if (uri.Port != -1) {
|
||||
// For HTTPS, the default port is 443. We only need to set the port explicitly
|
||||
// if we're not using HTTPS or if we're using a non-standard HTTPS port.
|
||||
if (scheme != "https" || uri.Port != 443) {
|
||||
data.SetAttribute("port", AndroidXmlNamespace, uri.Port.ToString());
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(uri.PathAndQuery) && uri.PathAndQuery != "/") {
|
||||
data.SetAttribute("path", AndroidXmlNamespace, uri.PathAndQuery);
|
||||
}
|
||||
|
||||
filter.AppendChild(data);
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d09054fcc76964295a49868566075973
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,346 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System;
|
||||
|
||||
public class UniWebViewGradleConfig
|
||||
{
|
||||
private readonly string m_filePath;
|
||||
|
||||
public UniWebViewGradleNode Root { get; }
|
||||
|
||||
public UniWebViewGradleConfig(string filePath)
|
||||
{
|
||||
var file = File.ReadAllText(filePath);
|
||||
TextReader reader = new StringReader(file);
|
||||
|
||||
m_filePath = filePath;
|
||||
Root = new UniWebViewGradleNode("root");
|
||||
var curNode = Root;
|
||||
|
||||
var str = new StringBuilder();
|
||||
var inDoubleQuote = false;
|
||||
var inSingleQuote = false;
|
||||
var inDollarVariable = false;
|
||||
|
||||
while (reader.Peek() > 0)
|
||||
{
|
||||
char c = (char)reader.Read();
|
||||
switch (c)
|
||||
{
|
||||
// case '/':
|
||||
// if (reader.Peek() == '/')
|
||||
// {
|
||||
// reader.Read();
|
||||
// string comment = reader.ReadLine();
|
||||
// Debug.Log("Comment line: " + comment);
|
||||
// curNode.AppendChildNode(new UniWebViewGradleCommentNode(comment, curNode));
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// str.Append('/');
|
||||
// }
|
||||
// break;
|
||||
case '\n':
|
||||
case '\r':
|
||||
{
|
||||
var strf = FormatStr(str);
|
||||
if (!string.IsNullOrEmpty(strf))
|
||||
{
|
||||
curNode.AppendChildNode(new UniWebViewGradleContentNode(strf, curNode));
|
||||
}
|
||||
}
|
||||
inDollarVariable = false;
|
||||
str = new StringBuilder();
|
||||
break;
|
||||
case '\t':
|
||||
{
|
||||
var strf = FormatStr(str);
|
||||
if (!string.IsNullOrEmpty(strf))
|
||||
{
|
||||
str.Append(" ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '{':
|
||||
{
|
||||
if (inDoubleQuote || inSingleQuote) {
|
||||
str.Append(c);
|
||||
break;
|
||||
}
|
||||
var n = FormatStr(str);
|
||||
if (!string.IsNullOrEmpty(n))
|
||||
{
|
||||
UniWebViewGradleNode node = new UniWebViewGradleNode(n, curNode);
|
||||
curNode.AppendChildNode(node);
|
||||
curNode = node;
|
||||
}
|
||||
}
|
||||
str = new StringBuilder();
|
||||
break;
|
||||
case '}':
|
||||
{
|
||||
if (inDoubleQuote || inSingleQuote) {
|
||||
str.Append(c);
|
||||
break;
|
||||
}
|
||||
var strf = FormatStr(str);
|
||||
if (!string.IsNullOrEmpty(strf))
|
||||
{
|
||||
curNode.AppendChildNode(new UniWebViewGradleContentNode(strf, curNode));
|
||||
}
|
||||
curNode = curNode.Parent;
|
||||
}
|
||||
str = new StringBuilder();
|
||||
break;
|
||||
case '\"':
|
||||
if (inDollarVariable) {
|
||||
str.Append(c);
|
||||
break;
|
||||
}
|
||||
inDoubleQuote = !inDoubleQuote;
|
||||
str.Append(c);
|
||||
break;
|
||||
case '\'':
|
||||
if (inDollarVariable) {
|
||||
str.Append(c);
|
||||
break;
|
||||
}
|
||||
inSingleQuote = !inSingleQuote;
|
||||
str.Append(c);
|
||||
break;
|
||||
case '$':
|
||||
{
|
||||
if (inDoubleQuote || inSingleQuote) {
|
||||
str.Append(c);
|
||||
break;
|
||||
}
|
||||
inDollarVariable = true;
|
||||
str.Append(c);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
str.Append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// End of file.
|
||||
var endline = FormatStr(str);
|
||||
if (!string.IsNullOrEmpty(endline))
|
||||
{
|
||||
curNode.AppendChildNode(new UniWebViewGradleContentNode(endline, curNode));
|
||||
}
|
||||
//Debug.Log("Gradle parse done!");
|
||||
}
|
||||
|
||||
public void Save(string path = null)
|
||||
{
|
||||
if (path == null) {
|
||||
path = m_filePath;
|
||||
}
|
||||
|
||||
File.WriteAllText(path, Print());
|
||||
}
|
||||
|
||||
private static string FormatStr(StringBuilder sb)
|
||||
{
|
||||
var str = sb.ToString();
|
||||
str = str.Trim();
|
||||
return str;
|
||||
}
|
||||
public string Print()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
PrintNode(sb, Root, -1);
|
||||
// Remove the first empty line.
|
||||
sb.Remove(0, 1);
|
||||
return sb.ToString();
|
||||
}
|
||||
private string GetLevelIndent(int level)
|
||||
{
|
||||
if (level <= 0) return "";
|
||||
StringBuilder sb = new StringBuilder("");
|
||||
for (int i = 0; i < level; i++)
|
||||
{
|
||||
sb.Append('\t');
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
private void PrintNode(StringBuilder stringBuilder, UniWebViewGradleNode node, int level)
|
||||
{
|
||||
if (node.Parent != null) {
|
||||
if (node is UniWebViewGradleCommentNode)
|
||||
{
|
||||
stringBuilder.Append("\n" + GetLevelIndent(level) + @"//" + node.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
stringBuilder.Append("\n" + GetLevelIndent(level) + node.Name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (node is UniWebViewGradleContentNode || node is UniWebViewGradleCommentNode) return;
|
||||
if (node.Parent != null) {
|
||||
stringBuilder.Append(" {");
|
||||
}
|
||||
foreach (var c in node.Children) {
|
||||
PrintNode(stringBuilder, c, level + 1);
|
||||
}
|
||||
if (node.Parent != null) {
|
||||
stringBuilder.Append("\n" + GetLevelIndent(level) + "}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class UniWebViewGradleNode
|
||||
{
|
||||
protected string m_name;
|
||||
public UniWebViewGradleNode Parent { get; private set; }
|
||||
|
||||
public string Name => m_name;
|
||||
|
||||
public List<UniWebViewGradleNode> Children { get; private set; } = new List<UniWebViewGradleNode>();
|
||||
|
||||
public UniWebViewGradleNode(string name, UniWebViewGradleNode parent = null)
|
||||
{
|
||||
Parent = parent;
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
public void Each(Action<UniWebViewGradleNode> f)
|
||||
{
|
||||
f(this);
|
||||
foreach (var n in Children)
|
||||
{
|
||||
n.Each(f);
|
||||
}
|
||||
}
|
||||
|
||||
public void AppendChildNode(UniWebViewGradleNode node)
|
||||
{
|
||||
if (Children == null) Children = new List<UniWebViewGradleNode>();
|
||||
Children.Add(node);
|
||||
node.Parent = this;
|
||||
}
|
||||
|
||||
public UniWebViewGradleNode TryGetNode(string path)
|
||||
{
|
||||
var subpath = path.Split('/');
|
||||
var cnode = this;
|
||||
foreach (var p in subpath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(p)) continue;
|
||||
var tnode = cnode.FindChildNodeByName(p);
|
||||
if (tnode == null)
|
||||
{
|
||||
Debug.Log("Can't find Node:" + p);
|
||||
return null;
|
||||
}
|
||||
|
||||
cnode = tnode;
|
||||
}
|
||||
|
||||
return cnode;
|
||||
}
|
||||
|
||||
public UniWebViewGradleNode FindChildNodeByName(string name)
|
||||
{
|
||||
foreach (var n in Children)
|
||||
{
|
||||
if (n is UniWebViewGradleCommentNode || n is UniWebViewGradleContentNode)
|
||||
continue;
|
||||
if (n.Name == name)
|
||||
return n;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool ReplaceContentStartsWith(string pattern, string value)
|
||||
{
|
||||
foreach (var n in Children)
|
||||
{
|
||||
if (!(n is UniWebViewGradleContentNode)) continue;
|
||||
if (n.m_name.StartsWith(pattern))
|
||||
{
|
||||
n.m_name = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public UniWebViewGradleContentNode ReplaceContentOrAddStartsWith(string pattern, string value)
|
||||
{
|
||||
foreach (var n in Children)
|
||||
{
|
||||
if (!(n is UniWebViewGradleContentNode)) continue;
|
||||
if (n.m_name.StartsWith(pattern))
|
||||
{
|
||||
n.m_name = value;
|
||||
return (UniWebViewGradleContentNode)n;
|
||||
}
|
||||
}
|
||||
return AppendContentNode(value);
|
||||
}
|
||||
|
||||
public UniWebViewGradleContentNode AppendContentNode(string content)
|
||||
{
|
||||
foreach (var n in Children)
|
||||
{
|
||||
if (!(n is UniWebViewGradleContentNode)) continue;
|
||||
if (n.m_name == content)
|
||||
{
|
||||
Debug.Log("UniWebViewGradleContentNode with " + content + " already exists!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
UniWebViewGradleContentNode cnode = new UniWebViewGradleContentNode(content, this);
|
||||
AppendChildNode(cnode);
|
||||
return cnode;
|
||||
}
|
||||
|
||||
|
||||
public bool RemoveContentNode(string contentPattern)
|
||||
{
|
||||
for(int i=0;i<Children.Count;i++)
|
||||
{
|
||||
if (!(Children[i] is UniWebViewGradleContentNode)) continue;
|
||||
if(Children[i].m_name.Contains(contentPattern))
|
||||
{
|
||||
Children.RemoveAt(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class UniWebViewGradleContentNode : UniWebViewGradleNode
|
||||
{
|
||||
public UniWebViewGradleContentNode(String content, UniWebViewGradleNode parent) : base(content, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void SetContent(string content)
|
||||
{
|
||||
m_name = content;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class UniWebViewGradleCommentNode : UniWebViewGradleNode
|
||||
{
|
||||
public UniWebViewGradleCommentNode(String content, UniWebViewGradleNode parent) : base(content, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string GetComment()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4a73a3268e19f44f7be818c5db9af457
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
public class UniWebViewGradlePropertyPatcher {
|
||||
|
||||
private readonly string filePath;
|
||||
private readonly UniWebViewEditorSettings settings;
|
||||
|
||||
// Construct a patcher with file path.
|
||||
public UniWebViewGradlePropertyPatcher(string filePath, UniWebViewEditorSettings settings)
|
||||
{
|
||||
this.filePath = filePath;
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
public void Patch()
|
||||
{
|
||||
var result = UpdatedString();
|
||||
File.WriteAllText(filePath, result);
|
||||
}
|
||||
|
||||
public string UpdatedString()
|
||||
{
|
||||
var lines = File.ReadAllLines(filePath);
|
||||
|
||||
var hasAndroidXProperty = lines.Any(text => text.Contains("android.useAndroidX"));
|
||||
var hasJetifierProperty = lines.Any(text => text.Contains("android.enableJetifier"));
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
foreach(var each in lines) {
|
||||
builder.AppendLine(each);
|
||||
}
|
||||
|
||||
if (!hasAndroidXProperty) {
|
||||
builder.AppendLine("android.useAndroidX=true");
|
||||
}
|
||||
|
||||
if (!hasJetifierProperty && settings.enableJetifier) {
|
||||
builder.AppendLine("android.enableJetifier=true");
|
||||
}
|
||||
|
||||
// AppendLine will add a new line at the end of the string, so we need to trim it to keep the file clean.
|
||||
return builder.ToString().Trim();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 62bf94600ac0f42c09fc261d7ab19e12
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
15
ProjectNLD/Assets/ThirdParty/UniWebView/Editor/UniWebView-CSharp.Editor.asmdef
vendored
Normal file
15
ProjectNLD/Assets/ThirdParty/UniWebView/Editor/UniWebView-CSharp.Editor.asmdef
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "UniWebView-CSharp.Editor",
|
||||
"references": ["GUID:343deaaf83e0cee4ca978e7df0b80d21","GUID:2bafac87e7f4b9b418d9448d219b01ab"],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
ProjectNLD/Assets/ThirdParty/UniWebView/Editor/UniWebView-CSharp.Editor.asmdef.meta
vendored
Normal file
7
ProjectNLD/Assets/ThirdParty/UniWebView/Editor/UniWebView-CSharp.Editor.asmdef.meta
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b6d0e5b49a073436cbcd56804553ee20
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
public class UniWebViewEditorSettings: ScriptableObject
|
||||
{
|
||||
private const string AssetPath = "Assets/Editor/UniWebView/settings.asset";
|
||||
|
||||
[SerializeField]
|
||||
internal bool usesCleartextTraffic = false;
|
||||
|
||||
[SerializeField]
|
||||
internal bool writeExternalStorage = false;
|
||||
|
||||
[SerializeField]
|
||||
internal bool accessFineLocation = false;
|
||||
|
||||
[SerializeField]
|
||||
internal bool addsKotlin = true;
|
||||
|
||||
[SerializeField]
|
||||
internal string kotlinVersion = null;
|
||||
|
||||
[SerializeField]
|
||||
internal bool addsAndroidBrowser = true;
|
||||
|
||||
[SerializeField]
|
||||
internal string androidBrowserVersion = null;
|
||||
|
||||
[SerializeField]
|
||||
internal bool addsAndroidXCore = false;
|
||||
|
||||
[SerializeField]
|
||||
internal string androidXCoreVersion = null;
|
||||
|
||||
[SerializeField]
|
||||
internal bool enableJetifier = true;
|
||||
|
||||
[SerializeField]
|
||||
internal string[] authCallbackUrls = { };
|
||||
|
||||
[SerializeField]
|
||||
internal bool supportLINELogin = false;
|
||||
|
||||
internal static string defaultKotlinVersion = "1.6.21";
|
||||
internal static string defaultAndroidBrowserVersion = "1.2.0";
|
||||
internal static string defaultAndroidXCoreVersion = "1.5.0";
|
||||
|
||||
internal static UniWebViewEditorSettings GetOrCreateSettings() {
|
||||
var settings = AssetDatabase.LoadAssetAtPath<UniWebViewEditorSettings>(AssetPath);
|
||||
|
||||
if (settings == null) {
|
||||
settings = ScriptableObject.CreateInstance<UniWebViewEditorSettings>();
|
||||
|
||||
Directory.CreateDirectory("Assets/Editor/UniWebView/");
|
||||
AssetDatabase.CreateAsset(settings, AssetPath);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
internal static SerializedObject GetSerializedSettings() {
|
||||
return new SerializedObject(GetOrCreateSettings());
|
||||
}
|
||||
}
|
||||
|
||||
// UniWebViewEditorSettings is not working well with AndroidProjectFilesModifier.
|
||||
// (reading it requires main thread, but the OnModifyAndroidProjectFiles is not in main thread)
|
||||
[Serializable]
|
||||
public class UniWebViewEditorSettingsReading {
|
||||
public bool usesCleartextTraffic = false;
|
||||
public bool writeExternalStorage = false;
|
||||
public bool accessFineLocation = false;
|
||||
public bool addsKotlin = true;
|
||||
public string kotlinVersion = null;
|
||||
public bool addsAndroidBrowser = true;
|
||||
public string androidBrowserVersion = null;
|
||||
public bool addsAndroidXCore = false;
|
||||
public string androidXCoreVersion = null;
|
||||
public bool enableJetifier = true;
|
||||
public string[] authCallbackUrls = { };
|
||||
public bool supportLINELogin = false;
|
||||
}
|
||||
|
||||
static class UniWebViewSettingsProvider {
|
||||
static SerializedObject settings;
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
private class Provider : SettingsProvider {
|
||||
public Provider(string path, SettingsScope scope = SettingsScope.User): base(path, scope) {}
|
||||
public override void OnGUI(string searchContext) {
|
||||
DrawPref();
|
||||
}
|
||||
}
|
||||
[SettingsProvider]
|
||||
static SettingsProvider UniWebViewPref() {
|
||||
return new Provider("Preferences/UniWebView");
|
||||
}
|
||||
#else
|
||||
[PreferenceItem("UniWebView")]
|
||||
#endif
|
||||
static void DrawPref() {
|
||||
EditorGUIUtility.labelWidth = 320;
|
||||
EditorGUIUtility.fieldWidth = 20;
|
||||
if (settings == null) {
|
||||
settings = UniWebViewEditorSettings.GetSerializedSettings();
|
||||
}
|
||||
settings.Update();
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
// Manifest
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.BeginVertical();
|
||||
EditorGUILayout.LabelField("Android Manifest", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(settings.FindProperty("usesCleartextTraffic"));
|
||||
DrawDetailLabel("If you need to load plain HTTP content.");
|
||||
|
||||
EditorGUILayout.PropertyField(settings.FindProperty("writeExternalStorage"));
|
||||
DrawDetailLabel("If you need to download an image from web page.");
|
||||
|
||||
EditorGUILayout.PropertyField(settings.FindProperty("accessFineLocation"));
|
||||
DrawDetailLabel("If you need to enable location support in web view.");
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
// Gradle
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.BeginVertical();
|
||||
EditorGUILayout.LabelField("Gradle Build", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(settings.FindProperty("addsKotlin"));
|
||||
DrawDetailLabel("Turn off this if another library is already adding Kotlin runtime.");
|
||||
var addingKotlin = settings.FindProperty("addsKotlin").boolValue;
|
||||
if (addingKotlin) {
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(settings.FindProperty("kotlinVersion"), GUILayout.Width(400));
|
||||
DrawDetailLabel("If not specified, use the default version: " + UniWebViewEditorSettings.defaultKotlinVersion);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(settings.FindProperty("addsAndroidBrowser"));
|
||||
DrawDetailLabel("Turn off this if another library is already adding 'androidx.browser:browser'.");
|
||||
var addingBrowser = settings.FindProperty("addsAndroidBrowser").boolValue;
|
||||
if (addingBrowser) {
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(settings.FindProperty("androidBrowserVersion"), GUILayout.Width(400));
|
||||
DrawDetailLabel("If not specified, use the default version: " + UniWebViewEditorSettings.defaultAndroidBrowserVersion);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
if (!addingBrowser) {
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
EditorGUILayout.HelpBox("UniWebView at least requires `androidx.core` to run. Without it, your game will crash when launching.\nIf you do not have another `androidx.core` package in the project, enable the option below.", MessageType.Warning);
|
||||
EditorGUILayout.PropertyField(settings.FindProperty("addsAndroidXCore"));
|
||||
DrawDetailLabel("Turn on this if you disabled `Adds Android Browser` and there is no other library adding 'androidx.core:core'.");
|
||||
var addingCore = settings.FindProperty("addsAndroidXCore").boolValue;
|
||||
if (addingCore) {
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(settings.FindProperty("androidXCoreVersion"), GUILayout.Width(400));
|
||||
DrawDetailLabel("If not specified, use the default version: " + UniWebViewEditorSettings.defaultAndroidXCoreVersion);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
|
||||
EditorGUILayout.PropertyField(settings.FindProperty("enableJetifier"));
|
||||
DrawDetailLabel("Turn off this if you do not need Jetifier (for converting other legacy support dependencies to Android X).");
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
// Auth callbacks
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.BeginVertical();
|
||||
EditorGUILayout.LabelField("Auth Callbacks", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(settings.FindProperty("authCallbackUrls"), true);
|
||||
DrawDetailLabel("Adds all available auth callback URLs here to use UniWebView's auth support.");
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.PropertyField(settings.FindProperty("supportLINELogin"));
|
||||
DrawDetailLabel("LINE Login is using a custom fixed scheme. If you want to support LINE Login, turn on this.");
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.HelpBox("Read the help page to know more about all UniWebView preferences detail.", MessageType.Info);
|
||||
|
||||
var style = new GUIStyle(GUI.skin.label);
|
||||
style.normal.textColor = Color.blue;
|
||||
if (GUILayout.Button("Help Page", style)) {
|
||||
Application.OpenURL("https://docs.uniwebview.com/guide/installation.html#optional-steps");
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (EditorGUI.EndChangeCheck()) {
|
||||
settings.ApplyModifiedProperties();
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
EditorGUIUtility.labelWidth = 0;
|
||||
}
|
||||
|
||||
static void DrawDetailLabel(string text) {
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.LabelField(text, EditorStyles.miniLabel);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
11
ProjectNLD/Assets/ThirdParty/UniWebView/Editor/UniWebViewEditorSettings.cs.meta
vendored
Normal file
11
ProjectNLD/Assets/ThirdParty/UniWebView/Editor/UniWebViewEditorSettings.cs.meta
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a403a09e241a0480a957591ea60fb785
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
334
ProjectNLD/Assets/ThirdParty/UniWebView/Editor/UniWebViewPostBuildProcessor.Android.cs
vendored
Normal file
334
ProjectNLD/Assets/ThirdParty/UniWebView/Editor/UniWebViewPostBuildProcessor.Android.cs
vendored
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
// #if UNITY_2023_2_OR_NEWER
|
||||
#if UNIWEBVIEW_NEW_ANDROID_BUILD_SYSTEM
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Unity.Android.Gradle;
|
||||
using Unity.Android.Gradle.Manifest;
|
||||
using UnityEditor.Android;
|
||||
using UnityEngine;
|
||||
using Action = Unity.Android.Gradle.Manifest.Action;
|
||||
|
||||
class UniWebViewPostBuildModifier : AndroidProjectFilesModifier {
|
||||
|
||||
const string ContextSettingsKey = "uniwebview_settings";
|
||||
|
||||
public override AndroidProjectFilesModifierContext Setup() {
|
||||
var context = new AndroidProjectFilesModifierContext {
|
||||
Dependencies = {
|
||||
DependencyFiles = new[] {
|
||||
// Set UniWebView editor settings asset path to be included in the build. With that we do not need
|
||||
// a clean build to update the settings anymore (maybe, not confirmed).
|
||||
UniWebViewEditorSettings.AssetPath
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var settings = UniWebViewEditorSettings.GetOrCreateSettings();
|
||||
context.SetData(ContextSettingsKey, settings);
|
||||
return context;
|
||||
}
|
||||
|
||||
public override void OnModifyAndroidProjectFiles(AndroidProjectFiles projectFiles) {
|
||||
var settings = projectFiles.GetData<UniWebViewEditorSettingsReading>(ContextSettingsKey);
|
||||
PatchUnityLibraryAndroidManifest(projectFiles.UnityLibraryManifest, settings);
|
||||
PatchUnityLibraryBuildGradle(projectFiles.UnityLibraryBuildGradle, settings);
|
||||
PatchGradleProperty(projectFiles.GradleProperties, settings);
|
||||
}
|
||||
|
||||
private void PatchUnityLibraryAndroidManifest(
|
||||
AndroidManifestFile manifest, UniWebViewEditorSettingsReading settings
|
||||
) {
|
||||
// Set hardwareAccelerated
|
||||
var launcherActivities = manifest.Manifest.GetActivitiesWithLauncherIntent();
|
||||
foreach (var activity in launcherActivities) {
|
||||
// Required for playing video in web view.
|
||||
activity.Attributes.HardwareAccelerated.Set(true);
|
||||
}
|
||||
|
||||
// Set usesCleartextTraffic
|
||||
if (settings.usesCleartextTraffic) {
|
||||
manifest.Manifest.Application.Attributes.UsesCleartextTraffic.Set(true);
|
||||
}
|
||||
|
||||
// Set WRITE_EXTERNAL_STORAGE permission
|
||||
if (settings.writeExternalStorage) {
|
||||
AddUsesPermission(manifest, "android.permission.WRITE_EXTERNAL_STORAGE");
|
||||
}
|
||||
|
||||
// Set ACCESS_FINE_LOCATION permission
|
||||
if (settings.accessFineLocation) {
|
||||
AddUsesPermission(manifest, "android.permission.ACCESS_FINE_LOCATION");
|
||||
}
|
||||
|
||||
// Set auth callback intent filter
|
||||
if (settings.authCallbackUrls.Length > 0 || settings.supportLINELogin) {
|
||||
var authActivity = new Activity();
|
||||
authActivity.Attributes.Name.Set("com.onevcat.uniwebview.UniWebViewAuthenticationActivity");
|
||||
authActivity.Attributes.Exported.Set(true);
|
||||
authActivity.Attributes.LaunchMode.Set(LaunchMode.SingleTask);
|
||||
authActivity.Attributes.ConfigChanges.Set(
|
||||
new[] {
|
||||
ConfigChanges.Orientation, ConfigChanges.ScreenSize, ConfigChanges.KeyboardHidden
|
||||
});
|
||||
|
||||
foreach (var url in settings.authCallbackUrls) {
|
||||
AddAuthCallbacksIntentFilter(authActivity, url);
|
||||
}
|
||||
if (settings.supportLINELogin) {
|
||||
AddAuthCallbacksIntentFilter(authActivity, "lineauth://auth");
|
||||
}
|
||||
manifest.Manifest.Application.ActivityList.AddElement(authActivity);
|
||||
}
|
||||
}
|
||||
|
||||
private void PatchUnityLibraryBuildGradle(ModuleBuildGradleFile gradleFile, UniWebViewEditorSettingsReading settings) {
|
||||
if (settings.addsKotlin) {
|
||||
var kotlinPrefix = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:";
|
||||
var kotlinVersion = String.IsNullOrWhiteSpace(settings.kotlinVersion)
|
||||
? UniWebViewEditorSettings.defaultKotlinVersion : settings.kotlinVersion;
|
||||
ReplaceContentOrAddStartsWith(gradleFile.Dependencies,
|
||||
kotlinPrefix,
|
||||
kotlinVersion);
|
||||
Debug.Log("<UniWebView> Updated Kotlin dependency in build.gradle.");
|
||||
}
|
||||
|
||||
if (settings.addsAndroidBrowser) {
|
||||
var browserPrefix = "androidx.browser:browser:";
|
||||
var browserVersion = String.IsNullOrWhiteSpace(settings.androidBrowserVersion)
|
||||
? UniWebViewEditorSettings.defaultAndroidBrowserVersion : settings.androidBrowserVersion;
|
||||
ReplaceContentOrAddStartsWith(gradleFile.Dependencies,
|
||||
browserPrefix,
|
||||
browserVersion);
|
||||
Debug.Log("<UniWebView> Updated Browser dependency in build.gradle.");
|
||||
}
|
||||
|
||||
if (!settings.addsAndroidBrowser && settings.addsAndroidXCore) {
|
||||
var androidXCorePrefix = "androidx.core:core:";
|
||||
var androidXCoreVersion = String.IsNullOrWhiteSpace(settings.androidXCoreVersion)
|
||||
? UniWebViewEditorSettings.defaultAndroidXCoreVersion : settings.androidXCoreVersion;
|
||||
ReplaceContentOrAddStartsWith(gradleFile.Dependencies,
|
||||
androidXCorePrefix,
|
||||
androidXCoreVersion);
|
||||
Debug.Log("<UniWebView> Updated Android X Core dependency in build.gradle.");
|
||||
}
|
||||
}
|
||||
|
||||
private void PatchGradleProperty(GradlePropertiesFile file, UniWebViewEditorSettingsReading settings) {
|
||||
var values = file.GetElements();
|
||||
foreach (var ele in values) {
|
||||
if (ele.GetRaw().Contains("android.enableJetifier")) {
|
||||
ele.SetRaw("android.enableJetifier=" + (settings.enableJetifier ? "true": "false"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddUsesPermission(AndroidManifestFile manifest, string name) {
|
||||
|
||||
var list = manifest.Manifest.UsesPermissionList;
|
||||
foreach (var item in list) {
|
||||
Debug.LogError(item.GetName());
|
||||
}
|
||||
|
||||
var existing = manifest.Manifest.UsesPermissionList
|
||||
.FirstOrDefault(ele => ele.Attributes.Name.Get() == name);
|
||||
if (existing != null) {
|
||||
return;
|
||||
}
|
||||
var permission = new UsesPermission();
|
||||
permission.Attributes.Name.Set(name);
|
||||
manifest.Manifest.UsesPermissionList.AddElement(permission);
|
||||
}
|
||||
|
||||
private void AddAuthCallbacksIntentFilter(Activity activity, string callbackUrl) {
|
||||
var uri = new Uri(callbackUrl);
|
||||
var scheme = uri.Scheme;
|
||||
|
||||
if (String.IsNullOrEmpty(scheme)) {
|
||||
Debug.LogError("<UniWebView> Auth callback url contains an empty scheme. Please check the url: " + callbackUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
var intentFilter = new IntentFilter();
|
||||
|
||||
var action = new Action();
|
||||
action.Attributes.Name.Set("android.intent.action.VIEW");
|
||||
intentFilter.ActionList.AddElement(action);
|
||||
|
||||
var defaultCategory = new Category();
|
||||
intentFilter.CategoryList.AddElement(defaultCategory);
|
||||
defaultCategory.Attributes.Name.Set("android.intent.category.DEFAULT");
|
||||
|
||||
var browsableCategory = new Category();
|
||||
browsableCategory.Attributes.Name.Set("android.intent.category.BROWSABLE");
|
||||
intentFilter.CategoryList.AddElement(browsableCategory);
|
||||
|
||||
var data = new Data();
|
||||
data.Attributes.Scheme.Set(scheme);
|
||||
if (!String.IsNullOrEmpty(uri.Host)) {
|
||||
data.Attributes.Host.Set(uri.Host);
|
||||
}
|
||||
if (uri.Port != -1) {
|
||||
data.Attributes.Port.Set(uri.Port.ToString());
|
||||
}
|
||||
if (!String.IsNullOrEmpty(uri.PathAndQuery) && uri.PathAndQuery != "/") {
|
||||
data.Attributes.Path.Set(uri.PathAndQuery);
|
||||
}
|
||||
intentFilter.DataList.AddElement(data);
|
||||
activity.IntentFilterList.AddElement(intentFilter);
|
||||
}
|
||||
|
||||
private void ReplaceContentOrAddStartsWith(Dependencies dependencies, string prefix, string version) {
|
||||
var all = dependencies.GetElements();
|
||||
var matching = "implementation '" + prefix;
|
||||
var found = all.FirstOrDefault(ele => ele.GetRaw().StartsWith(matching));
|
||||
if (found != null) {
|
||||
found.SetRaw($"implementation '{prefix}{version}'");
|
||||
} else {
|
||||
dependencies.AddDependencyImplementationRaw($"'{prefix}{version}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor.Android;
|
||||
using UnityEngine;
|
||||
|
||||
class UniWebViewPostBuildProcessor : IPostGenerateGradleAndroidProject
|
||||
{
|
||||
public int callbackOrder { get { return 1; } }
|
||||
public void OnPostGenerateGradleAndroidProject(string path) {
|
||||
Debug.Log("<UniWebView> UniWebView Post Build Script is patching manifest file and gradle file...");
|
||||
PatchAndroidManifest(path);
|
||||
PatchBuildGradle(path);
|
||||
PatchGradleProperty(path);
|
||||
}
|
||||
|
||||
private void PatchAndroidManifest(string root) {
|
||||
var manifestFilePath = GetManifestFilePath(root);
|
||||
var manifest = new UniWebViewAndroidManifest(manifestFilePath);
|
||||
|
||||
var changed = false;
|
||||
|
||||
Debug.Log("<UniWebView> Set hardware accelerated to enable smooth web view experience and HTML5 support like video and canvas.");
|
||||
changed = manifest.SetHardwareAccelerated() || changed;
|
||||
|
||||
var settings = UniWebViewEditorSettings.GetOrCreateSettings();
|
||||
if (settings.usesCleartextTraffic) {
|
||||
changed = manifest.SetUsesCleartextTraffic() || changed;
|
||||
}
|
||||
if (settings.writeExternalStorage) {
|
||||
changed = manifest.AddWriteExternalStoragePermission() || changed;
|
||||
}
|
||||
if (settings.accessFineLocation) {
|
||||
changed = manifest.AddAccessFineLocationPermission() || changed;
|
||||
}
|
||||
if (settings.authCallbackUrls.Length > 0) {
|
||||
changed = manifest.AddAuthCallbacksIntentFilter(settings.authCallbackUrls) || changed;
|
||||
}
|
||||
|
||||
if (settings.supportLINELogin) {
|
||||
changed = manifest.AddAuthCallbacksIntentFilter(new string[] { "lineauth://auth" }) || changed;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
manifest.Save();
|
||||
}
|
||||
}
|
||||
|
||||
private void PatchBuildGradle(string root) {
|
||||
var gradleFilePath = GetGradleFilePath(root);
|
||||
var config = new UniWebViewGradleConfig(gradleFilePath);
|
||||
|
||||
var settings = UniWebViewEditorSettings.GetOrCreateSettings();
|
||||
|
||||
var kotlinPrefix = "implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:";
|
||||
var kotlinVersion = String.IsNullOrWhiteSpace(settings.kotlinVersion)
|
||||
? UniWebViewEditorSettings.defaultKotlinVersion : settings.kotlinVersion;
|
||||
|
||||
var browserPrefix = "implementation 'androidx.browser:browser:";
|
||||
var browserVersion = String.IsNullOrWhiteSpace(settings.androidBrowserVersion)
|
||||
? UniWebViewEditorSettings.defaultAndroidBrowserVersion : settings.androidBrowserVersion;
|
||||
|
||||
var androidXCorePrefix = "implementation 'androidx.core:core:";
|
||||
var androidXCoreVersion = String.IsNullOrWhiteSpace(settings.androidXCoreVersion)
|
||||
? UniWebViewEditorSettings.defaultAndroidXCoreVersion : settings.androidXCoreVersion;
|
||||
|
||||
var dependenciesNode = config.Root.FindChildNodeByName("dependencies");
|
||||
if (dependenciesNode != null) {
|
||||
// Add kotlin
|
||||
if (settings.addsKotlin) {
|
||||
dependenciesNode.ReplaceContentOrAddStartsWith(kotlinPrefix, kotlinPrefix + kotlinVersion + "'");
|
||||
Debug.Log("<UniWebView> Updated Kotlin dependency in build.gradle.");
|
||||
}
|
||||
|
||||
// Add browser package
|
||||
if (settings.addsAndroidBrowser) {
|
||||
dependenciesNode.ReplaceContentOrAddStartsWith(browserPrefix, browserPrefix + browserVersion + "'");
|
||||
Debug.Log("<UniWebView> Updated Browser dependency in build.gradle.");
|
||||
}
|
||||
|
||||
// Add Android X Core package
|
||||
if (!settings.addsAndroidBrowser && settings.addsAndroidXCore) {
|
||||
// When adding android browser to the project, we don't need to add Android X Core package, since gradle resolves for it.
|
||||
dependenciesNode.ReplaceContentOrAddStartsWith(androidXCorePrefix, androidXCorePrefix + androidXCoreVersion + "'");
|
||||
Debug.Log("<UniWebView> Updated Android X Core dependency in build.gradle.");
|
||||
}
|
||||
} else {
|
||||
Debug.LogError("UniWebViewPostBuildProcessor didn't find the `dependencies` field in build.gradle.");
|
||||
Debug.LogError("Although we can continue to add a `dependencies`, make sure you have setup Gradle and the template correctly.");
|
||||
|
||||
var newNode = new UniWebViewGradleNode("dependencies", config.Root);
|
||||
if (settings.addsKotlin) {
|
||||
newNode.AppendContentNode(kotlinPrefix + kotlinVersion + "'");
|
||||
}
|
||||
if (settings.addsAndroidBrowser) {
|
||||
newNode.AppendContentNode(browserPrefix + browserVersion + "'");
|
||||
}
|
||||
|
||||
if (settings.addsAndroidXCore) {
|
||||
newNode.AppendContentNode(androidXCorePrefix + androidXCoreVersion + "'");
|
||||
}
|
||||
newNode.AppendContentNode("implementation(name: 'UniWebView', ext:'aar')");
|
||||
config.Root.AppendChildNode(newNode);
|
||||
}
|
||||
config.Save();
|
||||
}
|
||||
|
||||
private void PatchGradleProperty(string root) {
|
||||
var gradlePropertyFilePath = GetGradlePropertyFilePath(root);
|
||||
var patcher =
|
||||
new UniWebViewGradlePropertyPatcher(gradlePropertyFilePath, UniWebViewEditorSettings.GetOrCreateSettings());
|
||||
patcher.Patch();
|
||||
}
|
||||
|
||||
private string CombinePaths(string[] paths) {
|
||||
var path = "";
|
||||
foreach (var item in paths) {
|
||||
path = Path.Combine(path, item);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private string GetManifestFilePath(string root) {
|
||||
string[] comps = {root, "src", "main", "AndroidManifest.xml"};
|
||||
return CombinePaths(comps);
|
||||
}
|
||||
|
||||
private string GetGradleFilePath(string root) {
|
||||
string[] comps = {root, "build.gradle"};
|
||||
return CombinePaths(comps);
|
||||
}
|
||||
|
||||
private string GetGradlePropertyFilePath(string root) {
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
string[] compos = {root, "..", "gradle.properties"};
|
||||
#else
|
||||
string[] compos = {root, "gradle.properties"};
|
||||
#endif
|
||||
return CombinePaths(compos);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
11
ProjectNLD/Assets/ThirdParty/UniWebView/Editor/UniWebViewPostBuildProcessor.Android.cs.meta
vendored
Normal file
11
ProjectNLD/Assets/ThirdParty/UniWebView/Editor/UniWebViewPostBuildProcessor.Android.cs.meta
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fad245b203db64c21a4d1092e99ddc82
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
52
ProjectNLD/Assets/ThirdParty/UniWebView/Editor/UniWebViewPostBuildProcessor.iOS.cs
vendored
Normal file
52
ProjectNLD/Assets/ThirdParty/UniWebView/Editor/UniWebViewPostBuildProcessor.iOS.cs
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#if UNITY_IOS
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Callbacks;
|
||||
using UnityEditor.iOS.Xcode;
|
||||
|
||||
public class UniWebViewPostBuildProcessorIOS
|
||||
{
|
||||
[PostProcessBuild(1)]
|
||||
public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
|
||||
{
|
||||
if (target == BuildTarget.iOS) {
|
||||
var projectPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
|
||||
|
||||
var settings = UniWebViewEditorSettings.GetOrCreateSettings();
|
||||
if (settings.authCallbackUrls.Length > 0) {
|
||||
var domains = GetHttpsAssociatedDomains(settings.authCallbackUrls);
|
||||
if (domains.Length > 0) {
|
||||
Debug.Log("<UniWebView> UniWebView Post Build Script is patching associated domains for auth callbacks...");
|
||||
AddAssociatedDomain(projectPath, domains);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string[] GetHttpsAssociatedDomains(string[] urls) {
|
||||
return urls
|
||||
.Where(url => Uri.TryCreate(url, UriKind.Absolute, out Uri uri) && uri.Scheme == "https")
|
||||
.Select(url => new Uri(url).Host)
|
||||
.Distinct()
|
||||
.Select(domain => "applinks:" + domain)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public static void AddAssociatedDomain(string projectPath, string[] domains) {
|
||||
|
||||
PBXProject project = new PBXProject();
|
||||
project.ReadFromString(File.ReadAllText(projectPath));
|
||||
|
||||
var entitlementsFileName = "Unity-iPhone.entitlements";
|
||||
var targetGUID = project.GetUnityMainTargetGuid();
|
||||
var capabilityManager = new ProjectCapabilityManager(projectPath, entitlementsFileName, null, targetGUID);
|
||||
|
||||
capabilityManager.AddAssociatedDomains(domains);
|
||||
|
||||
capabilityManager.WriteToFile();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
11
ProjectNLD/Assets/ThirdParty/UniWebView/Editor/UniWebViewPostBuildProcessor.iOS.cs.meta
vendored
Normal file
11
ProjectNLD/Assets/ThirdParty/UniWebView/Editor/UniWebViewPostBuildProcessor.iOS.cs.meta
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 897910604e8514ad3b957c9039fd7531
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dc0f52a2d219347b1a6390b753d6ac97
|
||||
folderAsset: yes
|
||||
timeCreated: 1491898971
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,600 @@
|
|||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
class UniWebViewMethodChannel: AndroidJavaProxy {
|
||||
private const string GlobalChannelIdentifier = "__UniWebViewGlobalChannelIdentifier";
|
||||
public UniWebViewMethodChannel() : base("com.onevcat.uniwebview.UniWebViewNativeChannel") { }
|
||||
|
||||
string invokeChannelMethod(string name, string method, string parameters) {
|
||||
if (name == GlobalChannelIdentifier) {
|
||||
UniWebViewLogger.Instance.Verbose(
|
||||
"Global channel method invoked. Method: " + method + " Params: " + parameters
|
||||
);
|
||||
return UniWebViewStaticListener.InvokeStaticMethod(method, parameters);
|
||||
} else {
|
||||
UniWebViewLogger.Instance.Verbose("invokeChannelMethod invoked by native side. Name: " + name + " Method: "
|
||||
+ method + " Params: " + parameters);
|
||||
return UniWebViewChannelMethodManager.Instance.InvokeMethod(name, method, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class UniWebViewInterface {
|
||||
private static readonly AndroidJavaClass plugin;
|
||||
private static bool correctPlatform = Application.platform == RuntimePlatform.Android;
|
||||
|
||||
static UniWebViewInterface() {
|
||||
var go = new GameObject("UniWebViewAndroidStaticListener");
|
||||
go.AddComponent<UniWebViewAndroidStaticListener>();
|
||||
plugin = new AndroidJavaClass("com.onevcat.uniwebview.UniWebViewInterface");
|
||||
|
||||
CheckPlatform();
|
||||
|
||||
plugin.CallStatic("prepare");
|
||||
|
||||
UniWebViewLogger.Instance.Info("Connecting to native side method channel.");
|
||||
plugin.CallStatic("registerChannel", new UniWebViewMethodChannel());
|
||||
}
|
||||
|
||||
public static void SetLogLevel(int level) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setLogLevel", level);
|
||||
}
|
||||
|
||||
public static bool IsWebViewSupported() {
|
||||
CheckPlatform();
|
||||
return plugin.CallStatic<bool>("isWebViewSupported");
|
||||
}
|
||||
|
||||
public static void Init(string name, int x, int y, int width, int height) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("init", name, x, y, width, height);
|
||||
}
|
||||
|
||||
public static void Destroy(string name) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("destroy", name);
|
||||
}
|
||||
|
||||
public static void Load(string name, string url, bool skipEncoding, string readAccessURL) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("load", name, url);
|
||||
}
|
||||
|
||||
public static void LoadHTMLString(string name, string html, string baseUrl, bool skipEncoding) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("loadHTMLString", name, html, baseUrl);
|
||||
}
|
||||
|
||||
public static void Reload(string name) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("reload", name);
|
||||
}
|
||||
|
||||
public static void Stop(string name) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("stop", name);
|
||||
}
|
||||
|
||||
public static string GetUrl(string name) {
|
||||
CheckPlatform();
|
||||
return plugin.CallStatic<string>("getUrl", name);
|
||||
}
|
||||
|
||||
public static void SetFrame(string name, int x, int y, int width, int height) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setFrame", name, x, y, width, height);
|
||||
}
|
||||
|
||||
public static void SetPosition(string name, int x, int y) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setPosition", name, x, y);
|
||||
}
|
||||
|
||||
public static void SetSize(string name, int width, int height) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setSize", name, width, height);
|
||||
}
|
||||
|
||||
public static bool Show(string name, bool fade, int edge, float duration, bool useAsync, string identifier) {
|
||||
CheckPlatform();
|
||||
if (useAsync) {
|
||||
plugin.CallStatic("showAsync", name, fade, edge, duration, identifier);
|
||||
return true;
|
||||
} else {
|
||||
return plugin.CallStatic<bool>("show", name, fade, edge, duration, identifier);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Hide(string name, bool fade, int edge, float duration, bool useAsync, string identifier) {
|
||||
CheckPlatform();
|
||||
if (useAsync) {
|
||||
plugin.CallStatic("hideAsync", name, fade, edge, duration, identifier);
|
||||
return true;
|
||||
} else {
|
||||
return plugin.CallStatic<bool>("hide", name, fade, edge, duration, identifier);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool AnimateTo(string name, int x, int y, int width, int height, float duration, float delay, string identifier) {
|
||||
CheckPlatform();
|
||||
return plugin.CallStatic<bool>("animateTo", name, x, y, width, height, duration, delay, identifier);
|
||||
}
|
||||
|
||||
public static void AddJavaScript(string name, string jsString, string identifier) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("addJavaScript", name, jsString, identifier);
|
||||
}
|
||||
|
||||
public static void EvaluateJavaScript(string name, string jsString, string identifier) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("evaluateJavaScript", name, jsString, identifier);
|
||||
}
|
||||
|
||||
public static void AddUrlScheme(string name, string scheme) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("addUrlScheme", name, scheme);
|
||||
}
|
||||
|
||||
public static void RemoveUrlScheme(string name, string scheme) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("removeUrlScheme", name, scheme);
|
||||
}
|
||||
|
||||
public static void AddSslExceptionDomain(string name, string domain) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("addSslExceptionDomain", name, domain);
|
||||
}
|
||||
|
||||
public static void RemoveSslExceptionDomain(string name, string domain) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("removeSslExceptionDomain", name, domain);
|
||||
}
|
||||
|
||||
public static void AddPermissionTrustDomain(string name, string domain) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("addPermissionTrustDomain", name, domain);
|
||||
}
|
||||
|
||||
public static void RemovePermissionTrustDomain(string name, string domain) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("removePermissionTrustDomain", name, domain);
|
||||
}
|
||||
|
||||
public static void SetHeaderField(string name, string key, string value) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setHeaderField", name, key, value);
|
||||
}
|
||||
|
||||
public static void SetUserAgent(string name, string userAgent) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setUserAgent", name, userAgent);
|
||||
}
|
||||
|
||||
public static string GetUserAgent(string name) {
|
||||
CheckPlatform();
|
||||
return plugin.CallStatic<string>("getUserAgent", name);
|
||||
}
|
||||
|
||||
public static void SetAllowAutoPlay(bool flag) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setAllowAutoPlay", flag);
|
||||
}
|
||||
|
||||
public static void SetAllowJavaScriptOpenWindow(bool flag) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setAllowJavaScriptOpenWindow", flag);
|
||||
}
|
||||
|
||||
public static void SetAllowFileAccess(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setAllowFileAccess", name, flag);
|
||||
}
|
||||
|
||||
public static void SetAcceptThirdPartyCookies(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setAcceptThirdPartyCookies", name, flag);
|
||||
}
|
||||
|
||||
public static void SetAllowFileAccessFromFileURLs(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setAllowFileAccessFromFileURLs", name, flag);
|
||||
}
|
||||
|
||||
public static void SetAllowUniversalAccessFromFileURLs(bool flag) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setAllowUniversalAccessFromFileURLs", flag);
|
||||
}
|
||||
public static void BringContentToFront(string name) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("bringContentToFront", name);
|
||||
}
|
||||
|
||||
public static void SetForwardWebConsoleToNativeOutput(bool flag) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setForwardWebConsoleToNativeOutput", flag);
|
||||
}
|
||||
|
||||
public static void SetEnableKeyboardAvoidance(bool flag) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setEnableKeyboardAvoidance", flag);
|
||||
}
|
||||
|
||||
public static void SetJavaScriptEnabled(bool enabled) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setJavaScriptEnabled", enabled);
|
||||
}
|
||||
|
||||
public static void CleanCache(string name) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("cleanCache", name);
|
||||
}
|
||||
|
||||
public static void SetCacheMode(string name, int mode) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setCacheMode", name, mode);
|
||||
}
|
||||
|
||||
public static void ClearCookies() {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("clearCookies");
|
||||
}
|
||||
|
||||
public static void ClearCookies(string identifier) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("clearCookiesAsync", identifier);
|
||||
}
|
||||
|
||||
public static void SetCookie(string url, string cookie, bool skipEncoding) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setCookie", url, cookie);
|
||||
}
|
||||
|
||||
public static void SetCookie(string url, string cookie, bool skipEncoding, string identifier) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setCookieAsync", url, cookie, identifier);
|
||||
}
|
||||
|
||||
public static string GetCookie(string url, string key, bool skipEncoding) {
|
||||
CheckPlatform();
|
||||
return plugin.CallStatic<string>("getCookie", url, key);
|
||||
}
|
||||
|
||||
public static void GetCookie(string url, string key, bool skipEncoding, string identifier) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("getCookieAsync", url, key, identifier);
|
||||
}
|
||||
|
||||
public static void RemoveCookies(string url, bool skipEncoding) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("removeCookies", url);
|
||||
}
|
||||
|
||||
public static void RemoveCookies(string url, bool skipEncoding, string identifier) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("removeCookiesAsync", url, identifier);
|
||||
}
|
||||
|
||||
public static void RemoveCookie(string url, string key, bool skipEncoding) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("removeCookie", url, key);
|
||||
}
|
||||
|
||||
public static void RemoveCookie(string url, string key, bool skipEncoding, string identifier) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("removeCookieAsync", url, key, identifier);
|
||||
}
|
||||
|
||||
public static void ClearHttpAuthUsernamePassword(string host, string realm) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("clearHttpAuthUsernamePassword", host, realm);
|
||||
}
|
||||
|
||||
public static void SetBackgroundColor(string name, float r, float g, float b, float a) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setBackgroundColor", name, r, g, b, a);
|
||||
}
|
||||
|
||||
public static void SetWebViewAlpha(string name, float alpha) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setWebViewAlpha", name, alpha);
|
||||
}
|
||||
|
||||
public static float GetWebViewAlpha(string name) {
|
||||
CheckPlatform();
|
||||
return plugin.CallStatic<float>("getWebViewAlpha", name);
|
||||
}
|
||||
|
||||
public static void SetShowSpinnerWhileLoading(string name, bool show) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setShowSpinnerWhileLoading", name, show);
|
||||
}
|
||||
|
||||
public static void SetSpinnerText(string name, string text) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setSpinnerText", name, text);
|
||||
}
|
||||
|
||||
public static void SetAllowUserDismissSpinnerByGesture(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setAllowUserDismissSpinnerByGesture", name, flag);
|
||||
}
|
||||
|
||||
public static void ShowSpinner(string name) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("showSpinner", name);
|
||||
}
|
||||
|
||||
public static void HideSpinner(string name) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("hideSpinner", name);
|
||||
}
|
||||
|
||||
public static bool CanGoBack(string name) {
|
||||
CheckPlatform();
|
||||
return plugin.CallStatic<bool>("canGoBack", name);
|
||||
}
|
||||
|
||||
public static bool CanGoForward(string name) {
|
||||
CheckPlatform();
|
||||
return plugin.CallStatic<bool>("canGoForward", name);
|
||||
}
|
||||
|
||||
public static void GoBack(string name) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("goBack", name);
|
||||
}
|
||||
public static void GoForward(string name) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("goForward", name);
|
||||
}
|
||||
|
||||
public static void SetOpenLinksInExternalBrowser(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setOpenLinksInExternalBrowser", name, flag);
|
||||
}
|
||||
|
||||
public static void SetHorizontalScrollBarEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setHorizontalScrollBarEnabled", name, enabled);
|
||||
}
|
||||
|
||||
public static void SetVerticalScrollBarEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setVerticalScrollBarEnabled", name, enabled);
|
||||
}
|
||||
|
||||
public static void SetBouncesEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setBouncesEnabled", name, enabled);
|
||||
}
|
||||
|
||||
public static void SetZoomEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setZoomEnabled", name, enabled);
|
||||
}
|
||||
|
||||
public static void SetUseWideViewPort(string name, bool use) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setUseWideViewPort", name, use);
|
||||
}
|
||||
|
||||
public static void SetLoadWithOverviewMode(string name, bool overview) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setLoadWithOverviewMode", name, overview);
|
||||
}
|
||||
|
||||
public static void SetImmersiveModeEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setImmersiveModeEnabled", name, enabled);
|
||||
}
|
||||
|
||||
public static void SetUserInteractionEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setUserInteractionEnabled", name, enabled);
|
||||
}
|
||||
|
||||
public static void SetTransparencyClickingThroughEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setTransparencyClickingThroughEnabled", name, enabled);
|
||||
}
|
||||
|
||||
public static void SetWebContentsDebuggingEnabled(bool enabled) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setWebContentsDebuggingEnabled", enabled);
|
||||
}
|
||||
|
||||
public static void SetAllowHTTPAuthPopUpWindow(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setAllowHTTPAuthPopUpWindow", name, flag);
|
||||
}
|
||||
|
||||
public static void Print(string name) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("print", name);
|
||||
}
|
||||
|
||||
public static void CaptureSnapshot(string name, string filename) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("captureSnapshot", name, filename);
|
||||
}
|
||||
|
||||
public static void ScrollTo(string name, int x, int y, bool animated) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("scrollTo", name, x, y, animated);
|
||||
}
|
||||
|
||||
public static void SetCalloutEnabled(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setCalloutEnabled", name, flag);
|
||||
}
|
||||
|
||||
public static void SetSupportMultipleWindows(string name, bool enabled, bool allowJavaScriptOpening) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setSupportMultipleWindows", name, enabled, allowJavaScriptOpening);
|
||||
}
|
||||
|
||||
public static void SetDragInteractionEnabled(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setDragInteractionEnabled", name, flag);
|
||||
}
|
||||
|
||||
public static void SetDefaultFontSize(string name, int size) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setDefaultFontSize", name, size);
|
||||
}
|
||||
|
||||
public static void SetTextZoom(string name, int textZoom) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setTextZoom", name, textZoom);
|
||||
}
|
||||
|
||||
public static float NativeScreenWidth() {
|
||||
CheckPlatform();
|
||||
return plugin.CallStatic<float>("screenWidth");
|
||||
}
|
||||
|
||||
public static float NativeScreenHeight() {
|
||||
CheckPlatform();
|
||||
return plugin.CallStatic<float>("screenHeight");
|
||||
}
|
||||
|
||||
public static void SetDownloadEventForContextMenuEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setDownloadEventForContextMenuEnabled", name, enabled);
|
||||
}
|
||||
|
||||
public static void SetAllowUserEditFileNameBeforeDownloading(string name, bool allowed) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setAllowUserEditFileNameBeforeDownloading", name, allowed);
|
||||
}
|
||||
|
||||
// Safe Browsing
|
||||
|
||||
public static bool IsSafeBrowsingSupported() {
|
||||
CheckPlatform();
|
||||
return plugin.CallStatic<bool>("isSafeBrowsingSupported");
|
||||
}
|
||||
|
||||
public static void SafeBrowsingInit(string name, string url) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("safeBrowsingInit", name, url);
|
||||
}
|
||||
|
||||
public static void SafeBrowsingSetToolbarColor(string name, float r, float g, float b) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("safeBrowsingSetToolbarColor", name, r, g, b);
|
||||
}
|
||||
|
||||
public static void SafeBrowsingShow(string name) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("safeBrowsingShow", name);
|
||||
}
|
||||
|
||||
// Authentication
|
||||
|
||||
public static bool IsAuthenticationIsSupported() {
|
||||
CheckPlatform();
|
||||
return plugin.CallStatic<bool>("isAuthenticationIsSupported");
|
||||
}
|
||||
|
||||
public static void AuthenticationInit(string name, string url, string scheme) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("authenticationInit", name, url, scheme);
|
||||
}
|
||||
|
||||
public static void AuthenticationStart(string name) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("authenticationStart", name);
|
||||
}
|
||||
|
||||
public static void AuthenticationSetPrivateMode(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("authenticationSetPrivateMode", name, enabled);
|
||||
}
|
||||
|
||||
public static void SetShowEmbeddedToolbar(string name, bool show) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setShowEmbeddedToolbar", name, show);
|
||||
}
|
||||
|
||||
public static void SetEmbeddedToolbarOnTop(string name, bool top) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setEmbeddedToolbarOnTop", name, top);
|
||||
}
|
||||
|
||||
public static void SetEmbeddedToolbarDoneButtonText(string name, string text) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setEmbeddedToolbarDoneButtonText", name, text);
|
||||
}
|
||||
|
||||
public static void SetEmbeddedToolbarGoBackButtonText(string name, string text) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setEmbeddedToolbarGoBackButtonText", name, text);
|
||||
}
|
||||
|
||||
public static void SetEmbeddedToolbarGoForwardButtonText(string name, string text) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setEmbeddedToolbarGoForwardButtonText", name, text);
|
||||
}
|
||||
|
||||
public static void SetEmbeddedToolbarTitleText(string name, string text) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setEmbeddedToolbarTitleText", name, text);
|
||||
}
|
||||
|
||||
public static void SetEmbeddedToolbarBackgroundColor(string name, Color color) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setEmbeddedToolbarBackgroundColor", name, color.r, color.g, color.b, color.a);
|
||||
}
|
||||
|
||||
public static void SetEmbeddedToolbarButtonTextColor(string name, Color color) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setEmbeddedToolbarButtonTextColor", name, color.r, color.g, color.b, color.a);
|
||||
}
|
||||
|
||||
public static void SetEmbeddedToolbarTitleTextColor(string name, Color color) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setEmbeddedToolbarTitleTextColor", name, color.r, color.g, color.b, color.a);
|
||||
}
|
||||
|
||||
public static void SetEmeddedToolbarNavigationButtonsShow(string name, bool show) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("setEmbeddedToolbarNavigationButtonsShow", name, show);
|
||||
}
|
||||
|
||||
public static void StartSnapshotForRendering(string name, string identifier) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("startSnapshotForRendering", name, identifier);
|
||||
}
|
||||
|
||||
public static void StopSnapshotForRendering(string name) {
|
||||
CheckPlatform();
|
||||
plugin.CallStatic("stopSnapshotForRendering", name);
|
||||
}
|
||||
|
||||
public static byte[] GetRenderedData(string name, int x, int y, int width, int height) {
|
||||
CheckPlatform();
|
||||
var sbyteArray = plugin.CallStatic<sbyte[]>("getRenderedData", name, x, y, width, height);
|
||||
if (sbyteArray == null) {
|
||||
return null;
|
||||
}
|
||||
int length = sbyteArray.Length;
|
||||
byte[] byteArray = new byte[length];
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
byteArray[i] = (byte)sbyteArray[i];
|
||||
}
|
||||
return byteArray;
|
||||
}
|
||||
|
||||
// Platform
|
||||
|
||||
public static void CheckPlatform() {
|
||||
if (!correctPlatform) {
|
||||
throw new System.InvalidOperationException("Method can only be performed on Android.");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5a1d3cecc27d64565835e14b493c935b
|
||||
timeCreated: 1490880130
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
45
ProjectNLD/Assets/ThirdParty/UniWebView/Interface/UniWebViewAndroidStaticListener.cs
vendored
Normal file
45
ProjectNLD/Assets/ThirdParty/UniWebView/Interface/UniWebViewAndroidStaticListener.cs
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
// #if UNITY_ANDROID && !UNITY_EDITOR
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
public class UniWebViewAndroidStaticListener: MonoBehaviour {
|
||||
void Awake() {
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
|
||||
void OnJavaMessage(string message) {
|
||||
|
||||
UniWebViewLogger.Instance.Verbose(
|
||||
"Received message sent from native: " + message
|
||||
);
|
||||
|
||||
// {listener_name}@{method_name}@parameters
|
||||
var parts = message.Split("@"[0]);
|
||||
if (parts.Length < 3) {
|
||||
Debug.Log("Not enough parts for receiving a message.");
|
||||
return;
|
||||
}
|
||||
|
||||
var listener = UniWebViewNativeListener.GetListener(parts[0]);
|
||||
if (listener == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MethodInfo methodInfo = typeof(UniWebViewNativeListener).GetMethod(parts[1]);
|
||||
if (methodInfo == null) {
|
||||
Debug.Log("Cannot find correct method to invoke: " + parts[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
var leftLength = parts.Length - 2;
|
||||
var left = new string[leftLength];
|
||||
for (int i = 0; i < leftLength; i++) {
|
||||
left[i] = parts[i + 2];
|
||||
}
|
||||
methodInfo.Invoke(listener, new object[] { string.Join("@", left) });
|
||||
}
|
||||
}
|
||||
|
||||
// #endif
|
||||
13
ProjectNLD/Assets/ThirdParty/UniWebView/Interface/UniWebViewAndroidStaticListener.cs.meta
vendored
Normal file
13
ProjectNLD/Assets/ThirdParty/UniWebView/Interface/UniWebViewAndroidStaticListener.cs.meta
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2704cf8e127d541f1888d96429308645
|
||||
timeCreated: 1514387178
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,946 @@
|
|||
//
|
||||
// UniWebViewInterface.cs
|
||||
// Created by Wang Wei(@onevcat) on 2017-04-11.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
#if (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX || UNITY_IOS) && !UNITY_EDITOR_WIN && !UNITY_EDITOR_LINUX
|
||||
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using AOT;
|
||||
using System.Reflection;
|
||||
|
||||
public class UniWebViewInterface {
|
||||
|
||||
private const string StaticListenerName = "__UniWebViewGlobalListener";
|
||||
private const string GlobalChannelIdentifier = "__UniWebViewGlobalChannelIdentifier";
|
||||
|
||||
static UniWebViewInterface() {
|
||||
ConnectMessageSender();
|
||||
RegisterChannel();
|
||||
}
|
||||
|
||||
delegate void UnitySendMessageDelegate(IntPtr objectName, IntPtr methodName, IntPtr parameter);
|
||||
|
||||
private const string DllLib =
|
||||
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
|
||||
"UniWebView";
|
||||
#else
|
||||
"__Internal";
|
||||
#endif
|
||||
|
||||
private static bool correctPlatform =
|
||||
#if UNITY_EDITOR_OSX
|
||||
Application.platform == RuntimePlatform.OSXEditor ||
|
||||
Application.platform == RuntimePlatform.IPhonePlayer || // Support for Device Simulator package
|
||||
Application.platform == RuntimePlatform.Android; // Support for Device Simulator package
|
||||
#elif UNITY_STANDALONE_OSX
|
||||
Application.platform == RuntimePlatform.OSXPlayer;
|
||||
#else
|
||||
Application.platform == RuntimePlatform.IPhonePlayer;
|
||||
#endif
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_connectMessageSender(
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)] UnitySendMessageDelegate sendMessageDelegate
|
||||
);
|
||||
static void ConnectMessageSender() {
|
||||
UniWebViewLogger.Instance.Info("Connecting to native side message sender.");
|
||||
CheckPlatform();
|
||||
uv_connectMessageSender(SendMessage);
|
||||
}
|
||||
|
||||
[MonoPInvokeCallback(typeof(UnitySendMessageDelegate))]
|
||||
private static void SendMessage(IntPtr namePtr, IntPtr methodPtr, IntPtr parameterPtr) {
|
||||
string name = Marshal.PtrToStringAuto(namePtr);
|
||||
string method = Marshal.PtrToStringAuto(methodPtr);
|
||||
string parameters = Marshal.PtrToStringAuto(parameterPtr);
|
||||
|
||||
UniWebViewLogger.Instance.Verbose(
|
||||
"Received message sent from native. Name: " + name + " Method: " + method + " Params: " + parameters
|
||||
);
|
||||
|
||||
if (name == StaticListenerName) {
|
||||
UniWebViewStaticListener.InvokeStaticMethod(method, parameters);
|
||||
} else {
|
||||
var listener = UniWebViewNativeListener.GetListener(name);
|
||||
if (listener) {
|
||||
MethodInfo methodInfo = typeof(UniWebViewNativeListener).GetMethod(method);
|
||||
if (methodInfo != null) {
|
||||
methodInfo.Invoke(listener, new object[] { parameters });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delegate string ChannelMethodDelegate(IntPtr namePtr, IntPtr methodPtr, IntPtr parameterPtr);
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_registerChannel([MarshalAs(UnmanagedType.FunctionPtr)] ChannelMethodDelegate channel);
|
||||
public static void RegisterChannel() {
|
||||
UniWebViewLogger.Instance.Info("Connecting to native side method channel.");
|
||||
CheckPlatform();
|
||||
uv_registerChannel(ChannelFunc);
|
||||
}
|
||||
|
||||
[MonoPInvokeCallback(typeof(ChannelMethodDelegate))]
|
||||
private static string ChannelFunc(IntPtr namePtr, IntPtr methodPtr, IntPtr parameterPtr) {
|
||||
string name = Marshal.PtrToStringAuto(namePtr);
|
||||
string method = Marshal.PtrToStringAuto(methodPtr);
|
||||
string parameters = Marshal.PtrToStringAuto(parameterPtr);
|
||||
|
||||
// Shortcut for global channel method.
|
||||
if (name == GlobalChannelIdentifier) {
|
||||
UniWebViewLogger.Instance.Verbose(
|
||||
"Global channel method invoked. Method: " + method + " Params: " + parameters
|
||||
);
|
||||
return UniWebViewStaticListener.InvokeStaticMethod(method, parameters);
|
||||
} else {
|
||||
UniWebViewLogger.Instance.Verbose("ChannelFunc invoked by native side. Name: " + name + " Method: "
|
||||
+ method + " Params: " + parameters);
|
||||
return UniWebViewChannelMethodManager.Instance.InvokeMethod(name, method, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setLogLevel(int level);
|
||||
public static void SetLogLevel(int level) {
|
||||
CheckPlatform();
|
||||
uv_setLogLevel(level);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_init(string name, int x, int y, int width, int height);
|
||||
public static void Init(string name, int x, int y, int width, int height) {
|
||||
CheckPlatform();
|
||||
if (String.IsNullOrEmpty(name)) {
|
||||
return;
|
||||
}
|
||||
uv_init(name, x, y, width, height);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_destroy(string name);
|
||||
public static void Destroy(string name) {
|
||||
CheckPlatform();
|
||||
uv_destroy(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_load(string name, string url, bool skipEncoding, string readAccessURL);
|
||||
public static void Load(string name, string url, bool skipEncoding, string readAccessURL) {
|
||||
CheckPlatform();
|
||||
uv_load(name, url, skipEncoding, readAccessURL);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_loadHTMLString(string name, string html, string baseUrl, bool skipEncoding);
|
||||
public static void LoadHTMLString(string name, string html, string baseUrl, bool skipEncoding) {
|
||||
CheckPlatform();
|
||||
uv_loadHTMLString(name, html, baseUrl, skipEncoding);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_reload(string name);
|
||||
public static void Reload(string name) {
|
||||
CheckPlatform();
|
||||
uv_reload(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_stop(string name);
|
||||
public static void Stop(string name) {
|
||||
CheckPlatform();
|
||||
uv_stop(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern string uv_getUrl(string name);
|
||||
public static string GetUrl(string name) {
|
||||
CheckPlatform();
|
||||
return uv_getUrl(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setFrame(string name, int x, int y, int width, int height);
|
||||
public static void SetFrame(string name, int x, int y, int width, int height) {
|
||||
CheckPlatform();
|
||||
uv_setFrame(name, x, y, width, height);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setPosition(string name, int x, int y);
|
||||
public static void SetPosition(string name, int x, int y) {
|
||||
CheckPlatform();
|
||||
uv_setPosition(name, x, y);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setSize(string name, int width, int height);
|
||||
public static void SetSize(string name, int width, int height) {
|
||||
CheckPlatform();
|
||||
uv_setSize(name, width, height);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern bool uv_show(string name, bool fade, int edge, float duration, string identifier);
|
||||
public static bool Show(string name, bool fade, int edge, float duration, bool useAsync, string identifier) {
|
||||
CheckPlatform();
|
||||
return uv_show(name, fade, edge, duration, identifier);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern bool uv_hide(string name, bool fade, int edge, float duration, string identifier);
|
||||
public static bool Hide(string name, bool fade, int edge, float duration, bool useAsync, string identifier) {
|
||||
CheckPlatform();
|
||||
return uv_hide(name, fade, edge, duration, identifier);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern bool uv_animateTo(
|
||||
string name, int x, int y, int width, int height, float duration, float delay, string identifier
|
||||
);
|
||||
public static bool AnimateTo(
|
||||
string name, int x, int y, int width, int height, float duration, float delay, string identifier)
|
||||
{
|
||||
CheckPlatform();
|
||||
return uv_animateTo(name, x, y, width, height, duration, delay, identifier);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_addJavaScript(string name, string jsString, string identifier);
|
||||
public static void AddJavaScript(string name, string jsString, string identifier) {
|
||||
CheckPlatform();
|
||||
uv_addJavaScript(name, jsString, identifier);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_evaluateJavaScript(string name, string jsString, string identifier);
|
||||
public static void EvaluateJavaScript(string name, string jsString, string identifier) {
|
||||
CheckPlatform();
|
||||
uv_evaluateJavaScript(name, jsString, identifier);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_addUrlScheme(string name, string scheme);
|
||||
public static void AddUrlScheme(string name, string scheme) {
|
||||
CheckPlatform();
|
||||
uv_addUrlScheme(name, scheme);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_removeUrlScheme(string name, string scheme);
|
||||
public static void RemoveUrlScheme(string name, string scheme) {
|
||||
CheckPlatform();
|
||||
uv_removeUrlScheme(name, scheme);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_addSslExceptionDomain(string name, string domain);
|
||||
public static void AddSslExceptionDomain(string name, string domain) {
|
||||
CheckPlatform();
|
||||
uv_addSslExceptionDomain(name, domain);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_removeSslExceptionDomain(string name, string domain);
|
||||
public static void RemoveSslExceptionDomain(string name, string domain) {
|
||||
CheckPlatform();
|
||||
uv_removeSslExceptionDomain(name, domain);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setHeaderField(string name, string key, string value);
|
||||
public static void SetHeaderField(string name, string key, string value) {
|
||||
CheckPlatform();
|
||||
uv_setHeaderField(name, key, value);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setUserAgent(string name, string userAgent);
|
||||
public static void SetUserAgent(string name, string userAgent) {
|
||||
CheckPlatform();
|
||||
uv_setUserAgent(name, userAgent);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern string uv_getUserAgent(string name);
|
||||
public static string GetUserAgent(string name) {
|
||||
CheckPlatform();
|
||||
return uv_getUserAgent(name);
|
||||
}
|
||||
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setContentInsetAdjustmentBehavior(string name, int behavior);
|
||||
public static void SetContentInsetAdjustmentBehavior(
|
||||
string name, UniWebViewContentInsetAdjustmentBehavior behavior
|
||||
)
|
||||
{
|
||||
CheckPlatform();
|
||||
uv_setContentInsetAdjustmentBehavior(name, (int)behavior);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setAllowAutoPlay(bool flag);
|
||||
public static void SetAllowAutoPlay(bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setAllowAutoPlay(flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setAllowInlinePlay(bool flag);
|
||||
public static void SetAllowInlinePlay(bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setAllowInlinePlay(flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setAllowFileAccess(string name, bool flag);
|
||||
public static void SetAllowFileAccess(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setAllowFileAccess(name, flag);
|
||||
}
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setAllowFileAccessFromFileURLs(string name, bool flag);
|
||||
public static void SetAllowFileAccessFromFileURLs(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setAllowFileAccessFromFileURLs(name, flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setAllowUniversalAccessFromFileURLs(bool flag);
|
||||
public static void SetAllowUniversalAccessFromFileURLs(bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setAllowUniversalAccessFromFileURLs(flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setForwardWebConsoleToNativeOutput(bool flag);
|
||||
public static void SetForwardWebConsoleToNativeOutput(bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setForwardWebConsoleToNativeOutput(flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setAllowJavaScriptOpenWindow(bool flag);
|
||||
public static void SetAllowJavaScriptOpenWindow(bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setAllowJavaScriptOpenWindow(flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setJavaScriptEnabled(bool flag);
|
||||
public static void SetJavaScriptEnabled(bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setJavaScriptEnabled(flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setLimitsNavigationsToAppBoundDomains(bool flag);
|
||||
public static void SetLimitsNavigationsToAppBoundDomains(bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setLimitsNavigationsToAppBoundDomains(flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_cleanCache(string name);
|
||||
public static void CleanCache(string name) {
|
||||
CheckPlatform();
|
||||
uv_cleanCache(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setCacheMode(string name, int mode);
|
||||
public static void SetCacheMode(string name, int mode) {
|
||||
CheckPlatform();
|
||||
uv_setCacheMode(name, mode);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_clearCookies();
|
||||
public static void ClearCookies() {
|
||||
CheckPlatform();
|
||||
uv_clearCookies();
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_clearCookiesAsync(string identifier);
|
||||
public static void ClearCookies(string identifier) {
|
||||
CheckPlatform();
|
||||
uv_clearCookiesAsync(identifier);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setCookie(string url, string cookie, bool skipEncoding);
|
||||
public static void SetCookie(string url, string cookie, bool skipEncoding) {
|
||||
CheckPlatform();
|
||||
uv_setCookie(url, cookie, skipEncoding);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setCookieAsync(string url, string cookie, bool skipEncoding, string identifier);
|
||||
public static void SetCookie(string url, string cookie, bool skipEncoding, string identifier) {
|
||||
CheckPlatform();
|
||||
uv_setCookieAsync(url, cookie, skipEncoding, identifier);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_removeCookies(string url, bool skipEncoding);
|
||||
public static void RemoveCookies(string url, bool skipEncoding) {
|
||||
CheckPlatform();
|
||||
uv_removeCookies(url, skipEncoding);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_removeCookiesAsync(string url, bool skipEncoding, string identifier);
|
||||
public static void RemoveCookies(string url, bool skipEncoding, string identifier) {
|
||||
CheckPlatform();
|
||||
uv_removeCookiesAsync(url, skipEncoding, identifier);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_removeCookie(string url, string key, bool skipEncoding);
|
||||
public static void RemoveCookie(string url, string key, bool skipEncoding) {
|
||||
CheckPlatform();
|
||||
uv_removeCookie(url, key, skipEncoding);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_removeCookieAsync(string url, string key, bool skipEncoding, string identifier);
|
||||
public static void RemoveCookie(string url, string key, bool skipEncoding, string identifier) {
|
||||
CheckPlatform();
|
||||
uv_removeCookieAsync(url, key, skipEncoding, identifier);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern string uv_getCookie(string url, string key, bool skipEncoding);
|
||||
public static string GetCookie(string url, string key, bool skipEncoding) {
|
||||
CheckPlatform();
|
||||
return uv_getCookie(url, key, skipEncoding);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_getCookieAsync(string url, string key, bool skipEncoding, string identifier);
|
||||
public static void GetCookie(string url, string key, bool skipEncoding, string identifier) {
|
||||
CheckPlatform();
|
||||
uv_getCookieAsync(url, key, skipEncoding, identifier);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_clearHttpAuthUsernamePasswordHost(string host, string realm);
|
||||
public static void ClearHttpAuthUsernamePassword(string host, string realm) {
|
||||
CheckPlatform();
|
||||
uv_clearHttpAuthUsernamePasswordHost(host, realm);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setBackgroundColor(string name, float r, float g, float b, float a);
|
||||
public static void SetBackgroundColor(string name, float r, float g, float b, float a) {
|
||||
CheckPlatform();
|
||||
uv_setBackgroundColor(name, r, g, b, a);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setWebViewAlpha(string name, float alpha);
|
||||
public static void SetWebViewAlpha(string name, float alpha) {
|
||||
CheckPlatform();
|
||||
uv_setWebViewAlpha(name, alpha);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern float uv_getWebViewAlpha(string name);
|
||||
public static float GetWebViewAlpha(string name) {
|
||||
CheckPlatform();
|
||||
return uv_getWebViewAlpha(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setShowSpinnerWhileLoading(string name, bool show);
|
||||
public static void SetShowSpinnerWhileLoading(string name, bool show) {
|
||||
CheckPlatform();
|
||||
uv_setShowSpinnerWhileLoading(name, show);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setSpinnerText(string name, string text);
|
||||
public static void SetSpinnerText(string name, string text) {
|
||||
CheckPlatform();
|
||||
uv_setSpinnerText(name, text);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setAllowUserDismissSpinnerByGesture(string name, bool flag);
|
||||
public static void SetAllowUserDismissSpinnerByGesture(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setAllowUserDismissSpinnerByGesture(name, flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_showSpinner(string name);
|
||||
public static void ShowSpinner(string name) {
|
||||
CheckPlatform();
|
||||
uv_showSpinner(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_hideSpinner(string name);
|
||||
public static void HideSpinner(string name) {
|
||||
CheckPlatform();
|
||||
uv_hideSpinner(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern bool uv_canGoBack(string name);
|
||||
public static bool CanGoBack(string name) {
|
||||
CheckPlatform();
|
||||
return uv_canGoBack(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern bool uv_canGoForward(string name);
|
||||
public static bool CanGoForward(string name) {
|
||||
CheckPlatform();
|
||||
return uv_canGoForward(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_goBack(string name);
|
||||
public static void GoBack(string name) {
|
||||
CheckPlatform();
|
||||
uv_goBack(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_goForward(string name);
|
||||
public static void GoForward(string name) {
|
||||
CheckPlatform();
|
||||
uv_goForward(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setOpenLinksInExternalBrowser(string name, bool flag);
|
||||
public static void SetOpenLinksInExternalBrowser(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setOpenLinksInExternalBrowser(name, flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setHorizontalScrollBarEnabled(string name, bool enabled);
|
||||
public static void SetHorizontalScrollBarEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
uv_setHorizontalScrollBarEnabled(name, enabled);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setVerticalScrollBarEnabled(string name, bool enabled);
|
||||
public static void SetVerticalScrollBarEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
uv_setVerticalScrollBarEnabled(name, enabled);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setBouncesEnabled(string name, bool enabled);
|
||||
public static void SetBouncesEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
uv_setBouncesEnabled(name, enabled);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setZoomEnabled(string name, bool enabled);
|
||||
public static void SetZoomEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
uv_setZoomEnabled(name, enabled);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setWindowUserResizeEnabled(string name, bool enabled);
|
||||
public static void SetWindowUserResizeEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
uv_setWindowUserResizeEnabled(name, enabled);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setUserInteractionEnabled(string name, bool enabled);
|
||||
public static void SetUserInteractionEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
uv_setUserInteractionEnabled(name, enabled);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setTransparencyClickingThroughEnabled(string name, bool enabled);
|
||||
public static void SetTransparencyClickingThroughEnabled(string name, bool enabled) {
|
||||
CheckPlatform();
|
||||
uv_setTransparencyClickingThroughEnabled(name, enabled);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setWebContentsDebuggingEnabled(bool enabled);
|
||||
public static void SetWebContentsDebuggingEnabled(bool enabled) {
|
||||
CheckPlatform();
|
||||
uv_setWebContentsDebuggingEnabled(enabled);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setAllowBackForwardNavigationGestures(string name, bool flag);
|
||||
public static void SetAllowBackForwardNavigationGestures(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setAllowBackForwardNavigationGestures(name, flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setAllowHTTPAuthPopUpWindow(string name, bool flag);
|
||||
public static void SetAllowHTTPAuthPopUpWindow(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setAllowHTTPAuthPopUpWindow(name, flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_print(string name);
|
||||
public static void Print(string name) {
|
||||
CheckPlatform();
|
||||
uv_print(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_captureSnapshot(string name, string fileName);
|
||||
public static void CaptureSnapshot(string name, string fileName) {
|
||||
CheckPlatform();
|
||||
uv_captureSnapshot(name, fileName);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_scrollTo(string name, int x, int y, bool animated);
|
||||
public static void ScrollTo(string name, int x, int y, bool animated) {
|
||||
CheckPlatform();
|
||||
uv_scrollTo(name, x, y, animated);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setCalloutEnabled(string name, bool flag);
|
||||
public static void SetCalloutEnabled(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setCalloutEnabled(name, flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setSupportMultipleWindows(string name, bool enabled, bool allowJavaScriptOpening);
|
||||
public static void SetSupportMultipleWindows(string name, bool enabled, bool allowJavaScriptOpening) {
|
||||
CheckPlatform();
|
||||
uv_setSupportMultipleWindows(name, enabled, allowJavaScriptOpening);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setDragInteractionEnabled(string name, bool flag);
|
||||
public static void SetDragInteractionEnabled(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
uv_setDragInteractionEnabled(name, flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern float uv_nativeScreenWidth();
|
||||
public static float NativeScreenWidth() {
|
||||
#if UNITY_EDITOR_OSX
|
||||
return Screen.width;
|
||||
#else
|
||||
return uv_nativeScreenWidth();
|
||||
#endif
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern float uv_nativeScreenHeight();
|
||||
public static float NativeScreenHeight() {
|
||||
#if UNITY_EDITOR_OSX
|
||||
return Screen.height;
|
||||
#else
|
||||
return uv_nativeScreenHeight();
|
||||
#endif
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_addDownloadURL(string name, string urlString, int type);
|
||||
public static void AddDownloadURL(string name, string urlString, int type) {
|
||||
CheckPlatform();
|
||||
uv_addDownloadURL(name, urlString, type);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_removeDownloadURL(string name, string urlString, int type);
|
||||
public static void RemoveDownloadURL(string name, string urlString, int type) {
|
||||
CheckPlatform();
|
||||
uv_removeDownloadURL(name, urlString, type);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_addDownloadMIMEType(string name, string MIMEType, int type);
|
||||
public static void AddDownloadMIMEType(string name, string MIMEType, int type) {
|
||||
CheckPlatform();
|
||||
uv_addDownloadMIMEType(name, MIMEType, type);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_removeDownloadMIMETypes(string name, string MIMEType, int type);
|
||||
public static void RemoveDownloadMIMETypes(string name, string MIMEType, int type) {
|
||||
CheckPlatform();
|
||||
uv_removeDownloadMIMETypes(name, MIMEType, type);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setAllowUserEditFileNameBeforeDownloading(string name, bool allowed);
|
||||
public static void SetAllowUserEditFileNameBeforeDownloading(string name, bool allowed) {
|
||||
CheckPlatform();
|
||||
uv_setAllowUserEditFileNameBeforeDownloading(name, allowed);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setAllowUserChooseActionAfterDownloading(string name, bool allowed);
|
||||
public static void SetAllowUserChooseActionAfterDownloading(string name, bool allowed) {
|
||||
CheckPlatform();
|
||||
uv_setAllowUserChooseActionAfterDownloading(name, allowed);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_safeBrowsingInit(string name, string url);
|
||||
public static void SafeBrowsingInit(string name, string url) {
|
||||
CheckPlatform();
|
||||
if (String.IsNullOrEmpty(name)) {
|
||||
return;
|
||||
}
|
||||
uv_safeBrowsingInit(name, url);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_safeBrowsingShow(string name);
|
||||
public static void SafeBrowsingShow(string name) {
|
||||
CheckPlatform();
|
||||
uv_safeBrowsingShow(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_safeBrowsingSetToolbarColor(string name, float r, float g, float b);
|
||||
public static void SafeBrowsingSetToolbarColor(string name, float r, float g, float b) {
|
||||
CheckPlatform();
|
||||
uv_safeBrowsingSetToolbarColor(name, r, g, b);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_safeBrowsingSetToolbarItemColor(string name, float r, float g, float b);
|
||||
public static void SafeBrowsingSetToolbarItemColor(string name, float r, float g, float b) {
|
||||
CheckPlatform();
|
||||
uv_safeBrowsingSetToolbarItemColor(name, r, g, b);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_safeBrowsingDismiss(string name);
|
||||
public static void SafeBrowsingDismiss(string name) {
|
||||
CheckPlatform();
|
||||
uv_safeBrowsingDismiss(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern bool uv_authenticationIsSupported();
|
||||
public static bool IsAuthenticationIsSupported() {
|
||||
CheckPlatform();
|
||||
return uv_authenticationIsSupported();
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_authenticationInit(string name, string url, string scheme);
|
||||
public static void AuthenticationInit(string name, string url, string scheme) {
|
||||
CheckPlatform();
|
||||
uv_authenticationInit(name, url, scheme);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_authenticationStart(string name);
|
||||
public static void AuthenticationStart(string name) {
|
||||
CheckPlatform();
|
||||
uv_authenticationStart(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_authenticationCancel(string name);
|
||||
public static void AuthenticationCancel(string name) {
|
||||
CheckPlatform();
|
||||
uv_authenticationCancel(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_authenticationSetPrivateMode(string name, bool flag);
|
||||
public static void AuthenticationSetPrivateMode(string name, bool flag) {
|
||||
CheckPlatform();
|
||||
uv_authenticationSetPrivateMode(name, flag);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setShowEmbeddedToolbar(string name, bool show);
|
||||
public static void SetShowEmbeddedToolbar(string name, bool show) {
|
||||
CheckPlatform();
|
||||
uv_setShowEmbeddedToolbar(name, show);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setEmbeddedToolbarOnTop(string name, bool top);
|
||||
public static void SetEmbeddedToolbarOnTop(string name, bool top) {
|
||||
CheckPlatform();
|
||||
uv_setEmbeddedToolbarOnTop(name, top);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setEmbeddedToolbarDoneButtonText(string name, string text);
|
||||
public static void SetEmbeddedToolbarDoneButtonText(string name, string text) {
|
||||
CheckPlatform();
|
||||
uv_setEmbeddedToolbarDoneButtonText(name, text);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setEmbeddedToolbarGoBackButtonText(string name, string text);
|
||||
public static void SetEmbeddedToolbarGoBackButtonText(string name, string text) {
|
||||
CheckPlatform();
|
||||
uv_setEmbeddedToolbarGoBackButtonText(name, text);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setEmbeddedToolbarGoForwardButtonText(string name, string text);
|
||||
public static void SetEmbeddedToolbarGoForwardButtonText(string name, string text) {
|
||||
CheckPlatform();
|
||||
uv_setEmbeddedToolbarGoForwardButtonText(name, text);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setEmbeddedToolbarTitleText(string name, string text);
|
||||
public static void SetEmbeddedToolbarTitleText(string name, string text) {
|
||||
CheckPlatform();
|
||||
uv_setEmbeddedToolbarTitleText(name, text);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setEmbeddedToolbarBackgroundColor(string name, float r, float g, float b, float a);
|
||||
public static void SetEmbeddedToolbarBackgroundColor(string name, Color color) {
|
||||
CheckPlatform();
|
||||
uv_setEmbeddedToolbarBackgroundColor(name, color.r, color.g, color.b, color.a);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setEmbeddedToolbarButtonTextColor(string name, float r, float g, float b, float a);
|
||||
public static void SetEmbeddedToolbarButtonTextColor(string name, Color color) {
|
||||
CheckPlatform();
|
||||
uv_setEmbeddedToolbarButtonTextColor(name, color.r, color.g, color.b, color.a);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setEmbeddedToolbarTitleTextColor(string name, float r, float g, float b, float a);
|
||||
public static void SetEmbeddedToolbarTitleTextColor(string name, Color color) {
|
||||
CheckPlatform();
|
||||
uv_setEmbeddedToolbarTitleTextColor(name, color.r, color.g, color.b, color.a);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setEmbeddedToolbarNavigationButtonsShow(string name, bool show);
|
||||
public static void SetEmeddedToolbarNavigationButtonsShow(string name, bool show) {
|
||||
CheckPlatform();
|
||||
uv_setEmbeddedToolbarNavigationButtonsShow(name, show);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_startSnapshotForRendering(string name, string identifier);
|
||||
public static void StartSnapshotForRendering(string name, string identifier) {
|
||||
CheckPlatform();
|
||||
uv_startSnapshotForRendering(name, identifier);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_stopSnapshotForRendering(string name);
|
||||
public static void StopSnapshotForRendering(string name) {
|
||||
CheckPlatform();
|
||||
uv_stopSnapshotForRendering(name);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern IntPtr uv_getRenderedData(string name, int x, int y, int width, int height, out int length);
|
||||
public static byte[] GetRenderedData(string name, int x, int y, int width, int height) {
|
||||
CheckPlatform();
|
||||
|
||||
IntPtr dataPtr = uv_getRenderedData(name, x, y, width, height, out var length);
|
||||
|
||||
byte[] managedData = new byte[length];
|
||||
Marshal.Copy(dataPtr, managedData, 0, length);
|
||||
|
||||
return managedData;
|
||||
}
|
||||
|
||||
#region Deprecated
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setShowToolbar(string name, bool show, bool animated, bool onTop, bool adjustInset);
|
||||
public static void SetShowToolbar(string name, bool show, bool animated, bool onTop, bool adjustInset) {
|
||||
CheckPlatform();
|
||||
uv_setShowToolbar(name, show, animated, onTop, adjustInset);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setShowToolbarNavigationButtons(string name, bool show);
|
||||
public static void SetShowToolbarNavigationButtons(string name, bool show) {
|
||||
CheckPlatform();
|
||||
uv_setShowToolbarNavigationButtons(name, show);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setToolbarDoneButtonText(string name, string text);
|
||||
public static void SetToolbarDoneButtonText(string name, string text) {
|
||||
CheckPlatform();
|
||||
uv_setToolbarDoneButtonText(name, text);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setGoBackButtonText(string name, string text);
|
||||
public static void SetToolbarGoBackButtonText(string name, string text) {
|
||||
CheckPlatform();
|
||||
uv_setGoBackButtonText(name, text);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setGoForwardButtonText(string name, string text);
|
||||
public static void SetToolbarGoForwardButtonText(string name, string text) {
|
||||
CheckPlatform();
|
||||
uv_setGoForwardButtonText(name, text);
|
||||
}
|
||||
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setToolbarTintColor(string name, float r, float g, float b);
|
||||
public static void SetToolbarTintColor(string name, float r, float g, float b) {
|
||||
CheckPlatform();
|
||||
uv_setToolbarTintColor(name, r, g, b);
|
||||
}
|
||||
|
||||
[DllImport(DllLib)]
|
||||
private static extern void uv_setToolbarTextColor(string name, float r, float g, float b);
|
||||
public static void SetToolbarTextColor(string name, float r, float g, float b) {
|
||||
CheckPlatform();
|
||||
uv_setToolbarTextColor(name, r, g, b);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static void CheckPlatform() {
|
||||
if (!correctPlatform) {
|
||||
throw new System.InvalidOperationException(
|
||||
"Method can only be performed on correct platform. Current: " + Application.platform
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2e905ba0b47304f4cbf9e3e3345f84eb
|
||||
timeCreated: 1492400358
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
#if UNITY_EDITOR_WIN || UNITY_EDITOR_LINUX || (!UNITY_EDITOR_OSX && !UNITY_STANDALONE_OSX && !UNITY_IOS && !UNITY_ANDROID)
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
public class UniWebViewInterface {
|
||||
|
||||
private static bool alreadyLoggedWarning = false;
|
||||
|
||||
public static void SetLogLevel(int level) { CheckPlatform(); }
|
||||
public static void Init(string name, int x, int y, int width, int height) { CheckPlatform(); }
|
||||
public static void Destroy(string name) { CheckPlatform(); }
|
||||
public static void Load(string name, string url, bool skipEncoding, string readAccessURL) { CheckPlatform(); }
|
||||
public static void LoadHTMLString(string name, string html, string baseUrl, bool skipEncoding) { CheckPlatform(); }
|
||||
public static void Reload(string name) { CheckPlatform(); }
|
||||
public static void Stop(string name) { CheckPlatform(); }
|
||||
public static string GetUrl(string name) { CheckPlatform(); return ""; }
|
||||
public static void SetFrame(string name, int x, int y, int width, int height) { CheckPlatform(); }
|
||||
public static void SetPosition(string name, int x, int y) { CheckPlatform(); }
|
||||
public static void SetSize(string name, int width, int height) { CheckPlatform(); }
|
||||
public static bool Show(string name, bool fade, int edge, float duration, bool useAsync, string identifier) { CheckPlatform(); return false; }
|
||||
public static bool Hide(string name, bool fade, int edge, float duration, bool useAsync, string identifier) { CheckPlatform(); return false; }
|
||||
public static bool AnimateTo(string name, int x, int y, int width, int height, float duration, float delay, string identifier) { CheckPlatform(); return false; }
|
||||
public static void AddJavaScript(string name, string jsString, string identifier) { CheckPlatform(); }
|
||||
public static void EvaluateJavaScript(string name, string jsString, string identifier) { CheckPlatform(); }
|
||||
public static void AddUrlScheme(string name, string scheme) { CheckPlatform(); }
|
||||
public static void RemoveUrlScheme(string name, string scheme) { CheckPlatform(); }
|
||||
public static void AddSslExceptionDomain(string name, string domain) { CheckPlatform(); }
|
||||
public static void RemoveSslExceptionDomain(string name, string domain) { CheckPlatform(); }
|
||||
public static void SetHeaderField(string name, string key, string value) { CheckPlatform(); }
|
||||
public static void SetUserAgent(string name, string userAgent) { CheckPlatform(); }
|
||||
public static string GetUserAgent(string name) { CheckPlatform(); return ""; }
|
||||
public static void SetAllowAutoPlay(bool flag) { CheckPlatform(); }
|
||||
public static void SetAllowInlinePlay(bool flag) { CheckPlatform(); }
|
||||
public static void SetAllowJavaScriptOpenWindow(bool flag) { CheckPlatform(); }
|
||||
public static void SetForwardWebConsoleToNativeOutput(bool flag) { CheckPlatform(); }
|
||||
public static void SetAllowFileAccess(string name, bool flag) { CheckPlatform(); }
|
||||
public static void SetAllowFileAccessFromFileURLs(string name, bool flag) { CheckPlatform(); }
|
||||
public static void SetAllowUniversalAccessFromFileURLs(bool flag) { CheckPlatform(); }
|
||||
public static void SetJavaScriptEnabled(bool flag) { CheckPlatform(); }
|
||||
public static void SetLimitsNavigationsToAppBoundDomains(bool enabled) { CheckPlatform(); }
|
||||
public static void CleanCache(string name) { CheckPlatform(); }
|
||||
public static void SetCacheMode(string name, int mode) { CheckPlatform(); }
|
||||
public static void ClearCookies() { CheckPlatform(); }
|
||||
public static void ClearCookies(string identifier) { CheckPlatform(); }
|
||||
public static void SetCookie(string url, string cookie, bool skipEncoding) { CheckPlatform(); }
|
||||
public static void SetCookie(string url, string cookie, bool skipEncoding, string identifier) { CheckPlatform(); }
|
||||
public static void RemoveCookies(string url, bool skipEncoding) { CheckPlatform(); }
|
||||
public static void RemoveCookies(string url, bool skipEncoding, string identifier) { CheckPlatform(); }
|
||||
public static void RemoveCookie(string url, string key, bool skipEncoding) { CheckPlatform(); }
|
||||
public static void RemoveCookie(string url, string key, bool skipEncoding, string identifier) { CheckPlatform(); }
|
||||
public static string GetCookie(string url, string key, bool skipEncoding) { CheckPlatform(); return ""; }
|
||||
public static void GetCookie(string url, string key, bool skipEncoding, string identifier) { CheckPlatform(); }
|
||||
public static void ClearHttpAuthUsernamePassword(string host, string realm) { CheckPlatform(); }
|
||||
public static void SetBackgroundColor(string name, float r, float g, float b, float a) { CheckPlatform(); }
|
||||
public static void SetWebViewAlpha(string name, float alpha) { CheckPlatform(); }
|
||||
public static float GetWebViewAlpha(string name) { CheckPlatform(); return 0.0f; }
|
||||
public static void SetShowSpinnerWhileLoading(string name, bool show) { CheckPlatform(); }
|
||||
public static void SetSpinnerText(string name, string text) { CheckPlatform(); }
|
||||
public static void SetAllowUserDismissSpinnerByGesture(string name, bool flag) { CheckPlatform(); }
|
||||
public static void ShowSpinner(string name) { CheckPlatform(); }
|
||||
public static void HideSpinner(string name) { CheckPlatform(); }
|
||||
public static bool CanGoBack(string name) { CheckPlatform(); return false; }
|
||||
public static bool CanGoForward(string name) { CheckPlatform(); return false; }
|
||||
public static void GoBack(string name) { CheckPlatform(); }
|
||||
public static void GoForward(string name) { CheckPlatform(); }
|
||||
public static void SetOpenLinksInExternalBrowser(string name, bool flag) { CheckPlatform(); }
|
||||
public static void SetHorizontalScrollBarEnabled(string name, bool enabled) { CheckPlatform(); }
|
||||
public static void SetVerticalScrollBarEnabled(string name, bool enabled) { CheckPlatform(); }
|
||||
public static void SetBouncesEnabled(string name, bool enabled) { CheckPlatform(); }
|
||||
public static void SetZoomEnabled(string name, bool enabled) { CheckPlatform(); }
|
||||
public static void SetShowToolbar(string name, bool show, bool animated, bool onTop, bool adjustInset) { CheckPlatform(); }
|
||||
public static void SetToolbarDoneButtonText(string name, string text) { CheckPlatform(); }
|
||||
public static void SetToolbarGoBackButtonText(string name, string text) { CheckPlatform(); }
|
||||
public static void SetToolbarGoForwardButtonText(string name, string text) { CheckPlatform(); }
|
||||
public static void SetToolbarTintColor(string name, float r, float g, float b) { CheckPlatform(); }
|
||||
public static void SetToolbarTextColor(string name, float r, float g, float b) { CheckPlatform(); }
|
||||
public static void SetUserInteractionEnabled(string name, bool enabled) { CheckPlatform(); }
|
||||
public static void SetTransparencyClickingThroughEnabled(string name, bool enabled) { CheckPlatform(); }
|
||||
public static void SetWebContentsDebuggingEnabled(bool enabled) { CheckPlatform(); }
|
||||
public static void SetAllowHTTPAuthPopUpWindow(string name, bool flag) { CheckPlatform(); }
|
||||
public static void SetAllowUserEditFileNameBeforeDownloading(string name, bool allowed) { CheckPlatform(); }
|
||||
public static void Print(string name) { CheckPlatform(); }
|
||||
public static void CaptureSnapshot(string name, string filename) { CheckPlatform(); }
|
||||
public static void SetCalloutEnabled(string name, bool flag) { CheckPlatform(); }
|
||||
public static void SetSupportMultipleWindows(string name, bool enabled, bool allowJavaScriptOpening) { CheckPlatform(); }
|
||||
public static void SetDragInteractionEnabled(string name, bool flag) { CheckPlatform(); }
|
||||
public static void ScrollTo(string name, int x, int y, bool animated) { CheckPlatform(); }
|
||||
public static float NativeScreenWidth() { CheckPlatform(); return 0.0f; }
|
||||
public static float NativeScreenHeight() { CheckPlatform(); return 0.0f; }
|
||||
public static void SafeBrowsingInit(string name, string url) { CheckPlatform(); }
|
||||
public static void SafeBrowsingSetToolbarColor(string name, float r, float g, float b) { CheckPlatform(); }
|
||||
public static void SafeBrowsingShow(string name) { CheckPlatform(); }
|
||||
public static bool IsAuthenticationIsSupported() { CheckPlatform(); return false; }
|
||||
public static void AuthenticationInit(string name, string url, string scheme) { CheckPlatform(); }
|
||||
public static void AuthenticationStart(string name) { CheckPlatform(); }
|
||||
public static void AuthenticationSetPrivateMode(string name, bool enabled) { CheckPlatform(); }
|
||||
public static void SetShowEmbeddedToolbar(string name, bool show) { CheckPlatform(); }
|
||||
public static void SetEmbeddedToolbarOnTop(string name, bool top) { CheckPlatform(); }
|
||||
public static void SetEmbeddedToolbarDoneButtonText(string name, string text) { CheckPlatform(); }
|
||||
public static void SetEmbeddedToolbarGoBackButtonText(string name, string text) { CheckPlatform(); }
|
||||
public static void SetEmbeddedToolbarGoForwardButtonText(string name, string text) { CheckPlatform(); }
|
||||
public static void SetEmbeddedToolbarTitleText(string name, string text) { CheckPlatform(); }
|
||||
public static void SetEmbeddedToolbarBackgroundColor(string name, Color color) { CheckPlatform(); }
|
||||
public static void SetEmbeddedToolbarButtonTextColor(string name, Color color) { CheckPlatform(); }
|
||||
public static void SetEmbeddedToolbarTitleTextColor(string name, Color color) { CheckPlatform(); }
|
||||
public static void SetEmeddedToolbarNavigationButtonsShow(string name, bool show) { CheckPlatform(); }
|
||||
public static void StartSnapshotForRendering(string name, string identifier) { CheckPlatform(); }
|
||||
public static void StopSnapshotForRendering(string name) { CheckPlatform(); }
|
||||
public static byte[] GetRenderedData(string name, int x, int y, int width, int height) { CheckPlatform(); return null; }
|
||||
|
||||
public static void CheckPlatform() {
|
||||
if (!alreadyLoggedWarning) {
|
||||
alreadyLoggedWarning = true;
|
||||
Debug.LogWarning("UniWebView only supports iOS/Android/macOS Editor. You current platform " + Application.platform + " is not supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
12
ProjectNLD/Assets/ThirdParty/UniWebView/Interface/UniWebViewPlaceholder.cs.meta
vendored
Normal file
12
ProjectNLD/Assets/ThirdParty/UniWebView/Interface/UniWebViewPlaceholder.cs.meta
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0b3bad20d12b1433ab8927c3effc605b
|
||||
timeCreated: 1497403102
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c6b9d05744874ab45bf7e1c43c311952
|
||||
guid: 708b227955d014e9994cbb43756cffde
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a9dfaa2a98b494be99370d21c1d36be1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
|
@ -0,0 +1,32 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a70633e155d144f5da10d40c35d9c832
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Android: Android
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
fileFormatVersion: 2
|
||||
guid: db3f23043d1754d4b9c96ddb5ab457c9
|
||||
folderAsset: yes
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Standalone: OSXUniversal
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
ProjectNLD/Assets/ThirdParty/UniWebView/Plugins/UniWebView.bundle/Contents.meta
vendored
Normal file
8
ProjectNLD/Assets/ThirdParty/UniWebView/Plugins/UniWebView.bundle/Contents.meta
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 19150ffd969374afd9b181cd8c71f662
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
48
ProjectNLD/Assets/ThirdParty/UniWebView/Plugins/UniWebView.bundle/Contents/Info.plist
vendored
Normal file
48
ProjectNLD/Assets/ThirdParty/UniWebView/Plugins/UniWebView.bundle/Contents/Info.plist
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BuildMachineOSBuild</key>
|
||||
<string>24B91</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>UniWebView</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.onevcat.UniWebViewMac</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>UniWebView</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>MacOSX</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>DTCompiler</key>
|
||||
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||
<key>DTPlatformBuild</key>
|
||||
<string>24B75</string>
|
||||
<key>DTPlatformName</key>
|
||||
<string>macosx</string>
|
||||
<key>DTPlatformVersion</key>
|
||||
<string>15.1</string>
|
||||
<key>DTSDKBuild</key>
|
||||
<string>24B75</string>
|
||||
<key>DTSDKName</key>
|
||||
<string>macosx15.1</string>
|
||||
<key>DTXcode</key>
|
||||
<string>1610</string>
|
||||
<key>DTXcodeBuild</key>
|
||||
<string>16B40</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.11</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2017年 OneV's Den. All rights reserved.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
8
ProjectNLD/Assets/ThirdParty/UniWebView/Plugins/UniWebView.bundle/Contents/MacOS.meta
vendored
Normal file
8
ProjectNLD/Assets/ThirdParty/UniWebView/Plugins/UniWebView.bundle/Contents/MacOS.meta
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 495312126946747a3b197461eaff9687
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
ProjectNLD/Assets/ThirdParty/UniWebView/Plugins/UniWebView.bundle/Contents/MacOS/UniWebView
vendored
Normal file
BIN
ProjectNLD/Assets/ThirdParty/UniWebView/Plugins/UniWebView.bundle/Contents/MacOS/UniWebView
vendored
Normal file
Binary file not shown.
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 80fcb824c01d44613803213f4b1ed096
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>files</key>
|
||||
<dict/>
|
||||
<key>files2</key>
|
||||
<dict/>
|
||||
<key>rules</key>
|
||||
<dict>
|
||||
<key>^Resources/</key>
|
||||
<true/>
|
||||
<key>^Resources/.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Resources/Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^version.plist$</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>rules2</key>
|
||||
<dict>
|
||||
<key>.*\.dSYM($|/)</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>11</real>
|
||||
</dict>
|
||||
<key>^(.*/)?\.DS_Store$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>2000</real>
|
||||
</dict>
|
||||
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>10</real>
|
||||
</dict>
|
||||
<key>^.*</key>
|
||||
<true/>
|
||||
<key>^Info\.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^PkgInfo$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^Resources/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Resources/Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^[^/]+$</key>
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>10</real>
|
||||
</dict>
|
||||
<key>^embedded\.provisionprofile$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^version\.plist$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 892c68d7190664504a3f57774594f739
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
|
@ -0,0 +1,33 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 060e1768692e941c2aa0f7c9f9f10e32
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d5d657f2ee1114e20bccaace74235a99
|
||||
folderAsset: yes
|
||||
timeCreated: 1491898971
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1900085666445226
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4960404783511462}
|
||||
- component: {fileID: 114939446366399424}
|
||||
m_Layer: 0
|
||||
m_Name: UniWebView
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4960404783511462
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1900085666445226}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &114939446366399424
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1900085666445226}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 598e18fb001004a81960f552978ecf4e, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
urlOnStart:
|
||||
showOnStart: 1
|
||||
fullScreen: 1
|
||||
useToolbar: 0
|
||||
toolbarPosition: 0
|
||||
useEmbeddedToolbar: 1
|
||||
embeddedToolbarPosition: 0
|
||||
frame:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 0
|
||||
height: 0
|
||||
referenceRectTransform: {fileID: 0}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7e3f16a6f6303419cbd9837f6c746de4
|
||||
timeCreated: 1496204510
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
mainObjectFileID: 100100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
46
ProjectNLD/Assets/ThirdParty/UniWebView/Prefab/UniWebViewSafeBrowsing.prefab
vendored
Normal file
46
ProjectNLD/Assets/ThirdParty/UniWebView/Prefab/UniWebViewSafeBrowsing.prefab
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &8236771505572270655
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8236771505572270653}
|
||||
- component: {fileID: 8236771505572270654}
|
||||
m_Layer: 0
|
||||
m_Name: UniWebViewSafeBrowsing
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &8236771505572270653
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8236771505572270655}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &8236771505572270654
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8236771505572270655}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5843488507315421aa0a7d92c0604d10, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
url:
|
||||
7
ProjectNLD/Assets/ThirdParty/UniWebView/Prefab/UniWebViewSafeBrowsing.prefab.meta
vendored
Normal file
7
ProjectNLD/Assets/ThirdParty/UniWebView/Prefab/UniWebViewSafeBrowsing.prefab.meta
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2d6c4899a63004f16bb4f791176f4ad3
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# UniWebView
|
||||
|
||||
Thank you for purchasing UniWebView.
|
||||
|
||||
UniWebView is a Unity3D plugin built on native iOS/Android technology. It helps your users to enjoy web content and
|
||||
interact with your game through the web views.
|
||||
|
||||
## Documentation
|
||||
|
||||
To get started, please visit our documentation site: [https://docs.uniwebview.com](https://docs.uniwebview.com). You
|
||||
could find step-by-step guides on how to import UniWebView to your project, as well as some basic usage of this asset.
|
||||
You could also find a full script reference on the same site in this page: [https://docs.uniwebview.com/api/](https://docs.uniwebview.com/api/).
|
||||
|
||||
## Upgrading
|
||||
|
||||
All purchased customers could get all updates for the same major version for free. Please check the place you have
|
||||
purchased this asset to see whether there is an update or not. A release note is also contained in this asset, in the
|
||||
"CHANGELOG.md" file. You could also find the same version list in [this page](https://docs.uniwebview.com/release-note).
|
||||
|
||||
## Getting Support
|
||||
|
||||
For frequently asked questions, we have a page to answer them. If you encountered any problems while using UniWebView,
|
||||
we strongly suggest to visit the [FAQ page](https://docs.uniwebview.com/guide/faq.html) first. Also feel free to
|
||||
[submit a ticket](https://onevcat.atlassian.net/servicedesk/customer/portal/2) if you cannot find a solution, we will
|
||||
do our best to get you out!
|
||||
|
||||
## Other
|
||||
|
||||
For more information, please visit the [official web site](https://uniwebview.com) of UniWebView, or contact us through
|
||||
a ticket.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 95440ce70c5e14d6e96e166c45f7cf6d
|
||||
timeCreated: 1499302025
|
||||
licenseType: Store
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b34f36f9836464e04893f632434d0862
|
||||
folderAsset: yes
|
||||
timeCreated: 1491898971
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 43c2ab2efc7244e0293d0a1cb0d869e8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,551 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Calvin Rien
|
||||
*
|
||||
* Based on the JSON parser by Patrick van Bergen
|
||||
* http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html
|
||||
*
|
||||
* Simplified it so that it doesn't throw exceptions
|
||||
* and can be used in Unity iPhone with maximum code stripping.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace UniWebViewExternal {
|
||||
// Example usage:
|
||||
//
|
||||
// using UnityEngine;
|
||||
// using System.Collections;
|
||||
// using System.Collection
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// s.Generic;
|
||||
// using MiniJSON;
|
||||
//
|
||||
// public class MiniJSONTest : MonoBehaviour {
|
||||
// void Start () {
|
||||
// var jsonString = "{ \"array\": [1.44,2,3], " +
|
||||
// "\"object\": {\"key1\":\"value1\", \"key2\":256}, " +
|
||||
// "\"string\": \"The quick brown fox \\\"jumps\\\" over the lazy dog \", " +
|
||||
// "\"unicode\": \"\\u3041 Men\u00fa sesi\u00f3n\", " +
|
||||
// "\"int\": 65536, " +
|
||||
// "\"float\": 3.1415926, " +
|
||||
// "\"bool\": true, " +
|
||||
// "\"null\": null }";
|
||||
//
|
||||
// var dict = Json.Deserialize(jsonString) as Dictionary<string,object>;
|
||||
//
|
||||
// Debug.Log("deserialized: " + dict.GetType());
|
||||
// Debug.Log("dict['array'][0]: " + ((List<object>) dict["array"])[0]);
|
||||
// Debug.Log("dict['string']: " + (string) dict["string"]);
|
||||
// Debug.Log("dict['float']: " + (double) dict["float"]); // floats come out as doubles
|
||||
// Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs
|
||||
// Debug.Log("dict['unicode']: " + (string) dict["unicode"]);
|
||||
//
|
||||
// var str = Json.Serialize(dict);
|
||||
//
|
||||
// Debug.Log("serialized: " + str);
|
||||
// }
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// This class encodes and decodes JSON strings.
|
||||
/// Spec. details, see http://www.json.org/
|
||||
///
|
||||
/// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary.
|
||||
/// All numbers are parsed to doubles.
|
||||
/// </summary>
|
||||
public static class Json {
|
||||
/// <summary>
|
||||
/// Parses the string json into a value
|
||||
/// </summary>
|
||||
/// <param name="json">A JSON string.</param>
|
||||
/// <returns>An List<object>, a Dictionary<string, object>, a double, an integer,a string, null, true, or false</returns>
|
||||
public static object Deserialize(string json) {
|
||||
// save the string for debug information
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Parser.Parse(json);
|
||||
}
|
||||
|
||||
sealed class Parser : IDisposable {
|
||||
const string WORD_BREAK = "{}[],:\"";
|
||||
|
||||
public static bool IsWordBreak(char c) {
|
||||
return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1;
|
||||
}
|
||||
|
||||
enum TOKEN {
|
||||
NONE,
|
||||
CURLY_OPEN,
|
||||
CURLY_CLOSE,
|
||||
SQUARED_OPEN,
|
||||
SQUARED_CLOSE,
|
||||
COLON,
|
||||
COMMA,
|
||||
STRING,
|
||||
NUMBER,
|
||||
TRUE,
|
||||
FALSE,
|
||||
NULL
|
||||
};
|
||||
|
||||
StringReader json;
|
||||
|
||||
Parser(string jsonString) {
|
||||
json = new StringReader(jsonString);
|
||||
}
|
||||
|
||||
public static object Parse(string jsonString) {
|
||||
using (var instance = new Parser(jsonString)) {
|
||||
return instance.ParseValue();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
json.Dispose();
|
||||
json = null;
|
||||
}
|
||||
|
||||
Dictionary<string, object> ParseObject() {
|
||||
Dictionary<string, object> table = new Dictionary<string, object>();
|
||||
|
||||
// ditch opening brace
|
||||
json.Read();
|
||||
|
||||
// {
|
||||
while (true) {
|
||||
switch (NextToken) {
|
||||
case TOKEN.NONE:
|
||||
return null;
|
||||
case TOKEN.COMMA:
|
||||
continue;
|
||||
case TOKEN.CURLY_CLOSE:
|
||||
return table;
|
||||
default:
|
||||
// name
|
||||
string name = ParseString();
|
||||
if (name == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// :
|
||||
if (NextToken != TOKEN.COLON) {
|
||||
return null;
|
||||
}
|
||||
// ditch the colon
|
||||
json.Read();
|
||||
|
||||
// value
|
||||
table[name] = ParseValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<object> ParseArray() {
|
||||
List<object> array = new List<object>();
|
||||
|
||||
// ditch opening bracket
|
||||
json.Read();
|
||||
|
||||
// [
|
||||
var parsing = true;
|
||||
while (parsing) {
|
||||
TOKEN nextToken = NextToken;
|
||||
|
||||
switch (nextToken) {
|
||||
case TOKEN.NONE:
|
||||
return null;
|
||||
case TOKEN.COMMA:
|
||||
continue;
|
||||
case TOKEN.SQUARED_CLOSE:
|
||||
parsing = false;
|
||||
break;
|
||||
default:
|
||||
object value = ParseByToken(nextToken);
|
||||
|
||||
array.Add(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
object ParseValue() {
|
||||
TOKEN nextToken = NextToken;
|
||||
return ParseByToken(nextToken);
|
||||
}
|
||||
|
||||
object ParseByToken(TOKEN token) {
|
||||
switch (token) {
|
||||
case TOKEN.STRING:
|
||||
return ParseString();
|
||||
case TOKEN.NUMBER:
|
||||
return ParseNumber();
|
||||
case TOKEN.CURLY_OPEN:
|
||||
return ParseObject();
|
||||
case TOKEN.SQUARED_OPEN:
|
||||
return ParseArray();
|
||||
case TOKEN.TRUE:
|
||||
return true;
|
||||
case TOKEN.FALSE:
|
||||
return false;
|
||||
case TOKEN.NULL:
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
string ParseString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
char c;
|
||||
|
||||
// ditch opening quote
|
||||
json.Read();
|
||||
|
||||
bool parsing = true;
|
||||
while (parsing) {
|
||||
|
||||
if (json.Peek() == -1) {
|
||||
parsing = false;
|
||||
break;
|
||||
}
|
||||
|
||||
c = NextChar;
|
||||
switch (c) {
|
||||
case '"':
|
||||
parsing = false;
|
||||
break;
|
||||
case '\\':
|
||||
if (json.Peek() == -1) {
|
||||
parsing = false;
|
||||
break;
|
||||
}
|
||||
|
||||
c = NextChar;
|
||||
switch (c) {
|
||||
case '"':
|
||||
case '\\':
|
||||
case '/':
|
||||
s.Append(c);
|
||||
break;
|
||||
case 'b':
|
||||
s.Append('\b');
|
||||
break;
|
||||
case 'f':
|
||||
s.Append('\f');
|
||||
break;
|
||||
case 'n':
|
||||
s.Append('\n');
|
||||
break;
|
||||
case 'r':
|
||||
s.Append('\r');
|
||||
break;
|
||||
case 't':
|
||||
s.Append('\t');
|
||||
break;
|
||||
case 'u':
|
||||
var hex = new char[4];
|
||||
|
||||
for (int i=0; i< 4; i++) {
|
||||
hex[i] = NextChar;
|
||||
}
|
||||
|
||||
s.Append((char) Convert.ToInt32(new string(hex), 16));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
s.Append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return s.ToString();
|
||||
}
|
||||
|
||||
object ParseNumber() {
|
||||
string number = NextWord;
|
||||
|
||||
if (number.IndexOf('.') == -1) {
|
||||
long parsedInt;
|
||||
Int64.TryParse(number, out parsedInt);
|
||||
return parsedInt;
|
||||
}
|
||||
|
||||
double parsedDouble;
|
||||
Double.TryParse(number, out parsedDouble);
|
||||
return parsedDouble;
|
||||
}
|
||||
|
||||
void EatWhitespace() {
|
||||
while (Char.IsWhiteSpace(PeekChar)) {
|
||||
json.Read();
|
||||
|
||||
if (json.Peek() == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char PeekChar => Convert.ToChar(json.Peek());
|
||||
|
||||
char NextChar => Convert.ToChar(json.Read());
|
||||
|
||||
string NextWord {
|
||||
get {
|
||||
StringBuilder word = new StringBuilder();
|
||||
|
||||
while (!IsWordBreak(PeekChar)) {
|
||||
word.Append(NextChar);
|
||||
|
||||
if (json.Peek() == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return word.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
TOKEN NextToken {
|
||||
get {
|
||||
EatWhitespace();
|
||||
|
||||
if (json.Peek() == -1) {
|
||||
return TOKEN.NONE;
|
||||
}
|
||||
|
||||
switch (PeekChar) {
|
||||
case '{':
|
||||
return TOKEN.CURLY_OPEN;
|
||||
case '}':
|
||||
json.Read();
|
||||
return TOKEN.CURLY_CLOSE;
|
||||
case '[':
|
||||
return TOKEN.SQUARED_OPEN;
|
||||
case ']':
|
||||
json.Read();
|
||||
return TOKEN.SQUARED_CLOSE;
|
||||
case ',':
|
||||
json.Read();
|
||||
return TOKEN.COMMA;
|
||||
case '"':
|
||||
return TOKEN.STRING;
|
||||
case ':':
|
||||
return TOKEN.COLON;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '-':
|
||||
return TOKEN.NUMBER;
|
||||
}
|
||||
|
||||
switch (NextWord) {
|
||||
case "false":
|
||||
return TOKEN.FALSE;
|
||||
case "true":
|
||||
return TOKEN.TRUE;
|
||||
case "null":
|
||||
return TOKEN.NULL;
|
||||
}
|
||||
|
||||
return TOKEN.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string
|
||||
/// </summary>
|
||||
/// <param name="json">A Dictionary<string, object> / List<object></param>
|
||||
/// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
|
||||
public static string Serialize(object obj) {
|
||||
return Serializer.Serialize(obj);
|
||||
}
|
||||
|
||||
sealed class Serializer {
|
||||
StringBuilder builder;
|
||||
|
||||
Serializer() {
|
||||
builder = new StringBuilder();
|
||||
}
|
||||
|
||||
public static string Serialize(object obj) {
|
||||
var instance = new Serializer();
|
||||
|
||||
instance.SerializeValue(obj);
|
||||
|
||||
return instance.builder.ToString();
|
||||
}
|
||||
|
||||
void SerializeValue(object value) {
|
||||
IList asList;
|
||||
IDictionary asDict;
|
||||
string asStr;
|
||||
|
||||
if (value == null) {
|
||||
builder.Append("null");
|
||||
} else if ((asStr = value as string) != null) {
|
||||
SerializeString(asStr);
|
||||
} else if (value is bool) {
|
||||
builder.Append((bool) value ? "true" : "false");
|
||||
} else if ((asList = value as IList) != null) {
|
||||
SerializeArray(asList);
|
||||
} else if ((asDict = value as IDictionary) != null) {
|
||||
SerializeObject(asDict);
|
||||
} else if (value is char) {
|
||||
SerializeString(new string((char) value, 1));
|
||||
} else {
|
||||
SerializeOther(value);
|
||||
}
|
||||
}
|
||||
|
||||
void SerializeObject(IDictionary obj) {
|
||||
bool first = true;
|
||||
|
||||
builder.Append('{');
|
||||
|
||||
foreach (object e in obj.Keys) {
|
||||
if (!first) {
|
||||
builder.Append(',');
|
||||
}
|
||||
|
||||
SerializeString(e.ToString());
|
||||
builder.Append(':');
|
||||
|
||||
SerializeValue(obj[e]);
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
builder.Append('}');
|
||||
}
|
||||
|
||||
void SerializeArray(IList anArray) {
|
||||
builder.Append('[');
|
||||
|
||||
bool first = true;
|
||||
|
||||
foreach (object obj in anArray) {
|
||||
if (!first) {
|
||||
builder.Append(',');
|
||||
}
|
||||
|
||||
SerializeValue(obj);
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
builder.Append(']');
|
||||
}
|
||||
|
||||
void SerializeString(string str) {
|
||||
builder.Append('\"');
|
||||
|
||||
char[] charArray = str.ToCharArray();
|
||||
foreach (var c in charArray) {
|
||||
switch (c) {
|
||||
case '"':
|
||||
builder.Append("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
builder.Append("\\\\");
|
||||
break;
|
||||
case '\b':
|
||||
builder.Append("\\b");
|
||||
break;
|
||||
case '\f':
|
||||
builder.Append("\\f");
|
||||
break;
|
||||
case '\n':
|
||||
builder.Append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
builder.Append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
builder.Append("\\t");
|
||||
break;
|
||||
default:
|
||||
int codepoint = Convert.ToInt32(c);
|
||||
if ((codepoint >= 32) && (codepoint <= 126)) {
|
||||
builder.Append(c);
|
||||
} else {
|
||||
builder.Append("\\u");
|
||||
builder.Append(codepoint.ToString("x4"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
builder.Append('\"');
|
||||
}
|
||||
|
||||
void SerializeOther(object value) {
|
||||
// NOTE: decimals lose precision during serialization.
|
||||
// They always have, I'm just letting you know.
|
||||
// Previously floats and doubles lost precision too.
|
||||
if (value is float) {
|
||||
builder.Append(((float) value).ToString("R"));
|
||||
} else if (value is int
|
||||
|| value is uint
|
||||
|| value is long
|
||||
|| value is sbyte
|
||||
|| value is byte
|
||||
|| value is short
|
||||
|| value is ushort
|
||||
|| value is ulong) {
|
||||
builder.Append(value);
|
||||
} else if (value is double
|
||||
|| value is decimal) {
|
||||
builder.Append(Convert.ToDouble(value).ToString("R"));
|
||||
} else {
|
||||
SerializeString(value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f11796a30129b4c71aa6a52d59c6be19
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 598e18fb001004a81960f552978ecf4e
|
||||
timeCreated: 1491898971
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5b17dc622ffd649da85854192714e429
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
//
|
||||
// UniWebViewAuthenticationCommonFlow.cs
|
||||
// Created by Wang Wei (@onevcat) on 2022-06-25.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Abstract class and general control for other authentication flows. This class determines the global behaviors of the
|
||||
/// authentication flow, such as whether to start authentication as soon as the script `Start`s, and whether to use private
|
||||
/// mode to authenticate the user.
|
||||
|
||||
/// This is a super and abstract class for all concrete auth flow. You are not expected to use this class directly.
|
||||
/// Instead, to start a customized auth flow, you can use the `UniWebViewAuthenticationFlowCustomize` class.
|
||||
/// </summary>
|
||||
public abstract class UniWebViewAuthenticationCommonFlow: MonoBehaviour {
|
||||
/// <summary>
|
||||
/// Whether to start authentication as soon as the script `Start`s.
|
||||
/// </summary>
|
||||
public bool authorizeOnStart;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use private mode to authenticate the user. If `true` and the device supports, the authentication
|
||||
/// will begin under the incognito mode.
|
||||
///
|
||||
/// On iOS, this works on iOS 13 and later.
|
||||
///
|
||||
/// On Android, it depends on the Chrome version and might require users to enable the incognito mode (and support
|
||||
/// for third-party use) in Chrome's settings. Check settings with `chrome://flags/#cct-incognito` and
|
||||
/// `chrome://flags/#cct-incognito-available-to-third-party` in Chrome to see the current status.
|
||||
/// </summary>
|
||||
public bool privateMode;
|
||||
|
||||
// Security. Store the state.
|
||||
private string state;
|
||||
|
||||
// Security. Store the code challenge verifier.
|
||||
protected string CodeVerify { get; private set; }
|
||||
|
||||
public void Start() {
|
||||
if (authorizeOnStart) {
|
||||
StartAuthenticationFlow();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subclass should override this method to start the authentication flow. Usually it starts
|
||||
/// a `UniWebViewAuthenticationFlow`. But you can also choose whatever you need to do.
|
||||
/// </summary>
|
||||
public abstract void StartAuthenticationFlow();
|
||||
|
||||
/// <summary>
|
||||
/// Subclass should override this method to start the authentication flow. Usually it starts
|
||||
/// a Unity Web Request against the authentication flow's token entry point to refresh the token.
|
||||
/// </summary>
|
||||
/// <param name="refreshToken">The refresh token.</param>
|
||||
public abstract void StartRefreshTokenFlow(string refreshToken);
|
||||
|
||||
// Child classes are expected to call this method to request a `state` (and store it for later check) if the
|
||||
// `state` verification is enabled.
|
||||
protected string GenerateAndStoreState() {
|
||||
state = UniWebViewAuthenticationUtils.GenerateRandomBase64URLString();
|
||||
return state;
|
||||
}
|
||||
|
||||
// Child classes are expected to call this method to request a `code_challenge`. Later when exchanging the access
|
||||
// token, the `code_verifier` will be used to verify the `code_challenge`. Subclass can read it from `CodeVerify`.
|
||||
protected string GenerateCodeChallengeAndStoreCodeVerify(UniWebViewAuthenticationPKCE method) {
|
||||
CodeVerify = UniWebViewAuthenticationUtils.GenerateCodeVerifier();
|
||||
return UniWebViewAuthenticationUtils.CalculateCodeChallenge(CodeVerify, method);
|
||||
}
|
||||
|
||||
// Perform verifying for `state`.
|
||||
protected void VerifyState(Dictionary<string, string> parameters, string key = "state") {
|
||||
if (state == null) {
|
||||
throw AuthenticationResponseException.InvalidState;
|
||||
}
|
||||
if (!parameters.TryGetValue(key, out var stateInResponse) || state != stateInResponse) {
|
||||
throw AuthenticationResponseException.InvalidState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6bfa5bb9dc237400298563d614b62705
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,405 @@
|
|||
//
|
||||
// UniWebViewAuthenticationFlow.cs
|
||||
// Created by Wang Wei (@onevcat) on 2022-06-25.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine.Networking;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for implementing a custom authentication flow. An authentication flow, in UniWebView, usually a "code" based
|
||||
/// OAuth 2.0 flow, contains a standard set of steps:
|
||||
///
|
||||
/// 1. User is navigated to a web page that requires authentication;
|
||||
/// 2. A temporary code is generated by service provider and provided to client by a redirect URL with customized scheme.
|
||||
/// 3. Client requests an access token using the temporary code by performing an "access token" exchange request.
|
||||
///
|
||||
/// To use the common flow, any customize authentication flow must implement this interface and becomes a subclass of
|
||||
/// UniWebViewAuthenticationCommonFlow.
|
||||
/// </summary>
|
||||
/// <typeparam name="TTokenType"></typeparam>
|
||||
public interface IUniWebViewAuthenticationFlow<TTokenType>
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the redirect URL that is used to redirect the user after authenticated. This is used as the `redirect_uri`
|
||||
/// parameter when navigating user to the authentication page.
|
||||
///
|
||||
/// Usually this is a URL with customize scheme that later service provider may call. It takes intermediate code in its
|
||||
/// query and can be used to open the current app in client. The native side of UniWebView will catch and handle it,
|
||||
/// then send it to Unity side as the result of `UniWebViewAuthenticationSession`.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The redirect URL set in the OAuth settings.
|
||||
/// </returns>
|
||||
string GetCallbackUrl();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the config of the authentication flow. It usually defines the authentication requests entry points.
|
||||
/// </summary>
|
||||
/// <returns>The config object of an authentication flow.</returns>
|
||||
UniWebViewAuthenticationConfiguration GetAuthenticationConfiguration();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a dictionary contains the parameters that are used to perform the authentication request.
|
||||
/// The key value pairs in the dictionary are used to construct the query string of the authentication request.
|
||||
///
|
||||
/// This usually contains fields like `client_id`, `redirect_uri`, `response_type`, etc.
|
||||
/// </summary>
|
||||
/// <returns>The dictionary indicates parameters that are used to perform the authentication request.</returns>
|
||||
Dictionary<string, string> GetAuthenticationUriArguments();
|
||||
|
||||
/// <summary>
|
||||
/// Returns additional query arguments that are used to construct the query string of the authentication request.
|
||||
///
|
||||
/// If you want to add some extra query arguments to the authentication request, you can override this method and
|
||||
/// return a string that contains the additional query arguments. The returned string will be appended to the query
|
||||
/// string that constructed from `GetAuthenticationUriArguments`.
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The additional query arguments that are used to construct the query string of the authentication request.
|
||||
/// </returns>
|
||||
string GetAdditionalAuthenticationUriQuery();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a dictionary contains the parameters that are used to perform the access token exchange request.
|
||||
/// The key value pairs in the dictionary are used to construct the HTTP form body of the access token exchange request.
|
||||
/// </summary>
|
||||
/// <param name="authResponse">
|
||||
/// The response from authentication request. If the authentication succeeds, it is
|
||||
/// usually a custom scheme URL with a `code` query as its parameter. Base on this, you could construct the body of the
|
||||
/// access token exchange request.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The dictionary indicates parameters that are used to perform the access token exchange request.
|
||||
/// </returns>
|
||||
Dictionary<string, string> GetAccessTokenRequestParameters(string authResponse);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a dictionary contains the parameters that are used to perform the access token refresh request.
|
||||
/// The key value pairs in the dictionary are used to construct the HTTP form body of the access token refresh request.
|
||||
/// </summary>
|
||||
/// <param name="refreshToken">The refresh token should be used to perform the refresh request.</param>
|
||||
/// <returns>
|
||||
/// The dictionary indicates parameters that are used to perform the access token refresh request.
|
||||
/// </returns>
|
||||
Dictionary<string, string> GetRefreshTokenRequestParameters(string refreshToken);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the strong-typed token for the authentication process.
|
||||
///
|
||||
/// When the token exchange request finishes without problem, the response body will be passed to this method and
|
||||
/// any conforming class should construct the token object from the response body.
|
||||
/// </summary>
|
||||
/// <param name="exchangeResponse">
|
||||
/// The body response of the access token exchange request. Usually it contains the desired `access_token` and other
|
||||
/// necessary fields to describe the authenticated result.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A token object with `TToken` type that represents the authenticated result.
|
||||
/// </returns>
|
||||
TTokenType GenerateTokenFromExchangeResponse(string exchangeResponse);
|
||||
|
||||
/// <summary>
|
||||
/// Called when the authentication flow succeeds and a valid token is generated.
|
||||
/// </summary>
|
||||
UnityEvent<TTokenType> OnAuthenticationFinished { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Called when any error (including user cancellation) happens during the authentication flow.
|
||||
/// </summary>
|
||||
UnityEvent<long, string> OnAuthenticationErrored { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Called when the access token refresh request finishes and a valid refreshed token is generated.
|
||||
/// </summary>
|
||||
UnityEvent<TTokenType> OnRefreshTokenFinished { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Called when any error happens during the access token refresh flow.
|
||||
/// </summary>
|
||||
UnityEvent<long, string> OnRefreshTokenErrored { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The manager object of an authentication flow. This defines and runs the common flow of an authentication process
|
||||
/// with `code` response type.
|
||||
/// </summary>
|
||||
/// <typeparam name="TTokenType">The responsive token type expected for this authentication flow.</typeparam>
|
||||
public class UniWebViewAuthenticationFlow<TTokenType> {
|
||||
|
||||
private IUniWebViewAuthenticationFlow<TTokenType> service;
|
||||
private UniWebViewAuthenticationSession session;
|
||||
private Uri callbackUri;
|
||||
|
||||
public UniWebViewAuthenticationFlow(
|
||||
IUniWebViewAuthenticationFlow<TTokenType> service
|
||||
)
|
||||
{
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the authentication flow.
|
||||
/// </summary>
|
||||
public void StartAuth()
|
||||
{
|
||||
callbackUri = new Uri(service.GetCallbackUrl());
|
||||
var authUrl = GetAuthUrl();
|
||||
session = UniWebViewAuthenticationSession.Create(authUrl, callbackUri.Scheme);
|
||||
var flow = service as UniWebViewAuthenticationCommonFlow;
|
||||
if (flow != null && flow.privateMode) {
|
||||
session.SetPrivateMode(true);
|
||||
}
|
||||
|
||||
#if UNITY_IOS
|
||||
#if UNITY_EDITOR
|
||||
// Editor does not support deep link.
|
||||
UniWebViewLogger.Instance.Info("Seems you are trying to perform OAuth with a universal link. It is not supported in editor. Try on a real device.");
|
||||
#else
|
||||
// The callback URL seems to be a universal link. We need to handle it in a different way.
|
||||
if (callbackUri.Scheme == "https") {
|
||||
Application.deepLinkActivated += HandleUniversalLink;
|
||||
}
|
||||
|
||||
#endif // UNITY_EDITOR
|
||||
#endif // UNITY_IOS
|
||||
|
||||
session.OnAuthenticationFinished += (_, resultUrl) => {
|
||||
UniWebViewLogger.Instance.Verbose("Auth flow received callback url: " + resultUrl);
|
||||
ExchangeToken(resultUrl);
|
||||
Application.deepLinkActivated -= HandleUniversalLink;
|
||||
};
|
||||
|
||||
session.OnAuthenticationErrorReceived += (_, errorCode, message) => {
|
||||
UniWebViewLogger.Instance.Verbose("Auth flow received error: " + errorCode + ". Detail: " + message);
|
||||
ExchangeTokenErrored(errorCode, message);
|
||||
Application.deepLinkActivated -= HandleUniversalLink;
|
||||
};
|
||||
|
||||
UniWebViewLogger.Instance.Verbose("Starting auth flow with url: " + authUrl + "; Callback scheme: " + callbackUri.Scheme);
|
||||
session.Start();
|
||||
}
|
||||
|
||||
private void HandleUniversalLink(string url) {
|
||||
if (callbackUri == null)
|
||||
{
|
||||
UniWebViewLogger.Instance.Critical("Callback URI is not set. Skip handling universal link. Make " +
|
||||
"sure you have set a correct callback URL.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (url.StartsWith(callbackUri.ToString(), StringComparison.InvariantCultureIgnoreCase)) {
|
||||
UniWebViewLogger.Instance.Verbose("HandleUniversalLink: " + url);
|
||||
Application.deepLinkActivated -= HandleUniversalLink;
|
||||
session.Cancel();
|
||||
ExchangeToken(url);
|
||||
}
|
||||
}
|
||||
|
||||
private void ExchangeToken(string response) {
|
||||
try {
|
||||
var args = service.GetAccessTokenRequestParameters(response);
|
||||
var request = GetTokenRequest(args);
|
||||
MonoBehaviour context = (MonoBehaviour)service;
|
||||
context.StartCoroutine(SendExchangeTokenRequest(request));
|
||||
} catch (Exception e) {
|
||||
var message = e.Message;
|
||||
var code = -1;
|
||||
if (e is AuthenticationResponseException ex) {
|
||||
code = ex.Code;
|
||||
}
|
||||
UniWebViewLogger.Instance.Critical("Exception on exchange token response: " + e + ". Code: " + code + ". Message: " + message);
|
||||
ExchangeTokenErrored(code, message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh the access token with the given refresh token.
|
||||
/// </summary>
|
||||
/// <param name="refreshToken"></param>
|
||||
public void RefreshToken(string refreshToken) {
|
||||
try {
|
||||
var args = service.GetRefreshTokenRequestParameters(refreshToken);
|
||||
var request = GetTokenRequest(args);
|
||||
MonoBehaviour context = (MonoBehaviour)service;
|
||||
context.StartCoroutine(SendRefreshTokenRequest(request));
|
||||
} catch (Exception e) {
|
||||
var message = e.Message;
|
||||
var code = -1;
|
||||
if (e is AuthenticationResponseException ex) {
|
||||
code = ex.Code;
|
||||
}
|
||||
UniWebViewLogger.Instance.Critical("Exception on refresh token response: " + e + ". Code: " + code + ". Message: " + message);
|
||||
RefreshTokenErrored(code, message);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetAuthUrl() {
|
||||
var builder = new UriBuilder(service.GetAuthenticationConfiguration().authorizationEndpoint);
|
||||
var query = new Dictionary<string, string>();
|
||||
foreach (var kv in service.GetAuthenticationUriArguments()) {
|
||||
query.Add(kv.Key, kv.Value);
|
||||
}
|
||||
var additionalQuery = service.GetAdditionalAuthenticationUriQuery();
|
||||
builder.Query = UniWebViewAuthenticationUtils.CreateQueryString(query, additionalQuery);
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private UnityWebRequest GetTokenRequest(Dictionary<string, string>args) {
|
||||
var builder = new UriBuilder(service.GetAuthenticationConfiguration().tokenEndpoint);
|
||||
var form = new WWWForm();
|
||||
foreach (var kv in args) {
|
||||
form.AddField(kv.Key, kv.Value);
|
||||
}
|
||||
return UnityWebRequest.Post(builder.ToString(), form);
|
||||
}
|
||||
|
||||
private IEnumerator SendExchangeTokenRequest(UnityWebRequest request) {
|
||||
return SendTokenRequest(request, ExchangeTokenFinished, ExchangeTokenErrored);
|
||||
}
|
||||
|
||||
private IEnumerator SendRefreshTokenRequest(UnityWebRequest request) {
|
||||
return SendTokenRequest(request, RefreshTokenFinished, RefreshTokenErrored);
|
||||
}
|
||||
|
||||
private IEnumerator SendTokenRequest(UnityWebRequest request, Action<TTokenType> finishAction, Action<long, string>errorAction)
|
||||
{
|
||||
using var www = request;
|
||||
yield return www.SendWebRequest();
|
||||
if (www.result != UnityWebRequest.Result.Success) {
|
||||
string errorMessage = null;
|
||||
string errorBody = null;
|
||||
if (www.error != null) {
|
||||
errorMessage = www.error;
|
||||
}
|
||||
if (www.downloadHandler != null && www.downloadHandler.text != null) {
|
||||
errorBody = www.downloadHandler.text;
|
||||
}
|
||||
UniWebViewLogger.Instance.Critical("Failed to get access token. Error: " + errorMessage + ". " + errorBody);
|
||||
errorAction(www.responseCode, errorBody ?? errorMessage);
|
||||
} else {
|
||||
var responseText = www.downloadHandler.text;
|
||||
UniWebViewLogger.Instance.Info("Token exchange request succeeded. Response: " + responseText);
|
||||
try {
|
||||
var token = service.GenerateTokenFromExchangeResponse(www.downloadHandler.text);
|
||||
finishAction(token);
|
||||
} catch (Exception e) {
|
||||
var message = e.Message;
|
||||
var code = -1;
|
||||
if (e is AuthenticationResponseException ex) {
|
||||
code = ex.Code;
|
||||
}
|
||||
UniWebViewLogger.Instance.Critical(
|
||||
"Exception on parsing token response: " + e + ". Code: " + code + ". Message: " +
|
||||
message + ". Response: " + responseText);
|
||||
errorAction(code, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ExchangeTokenFinished(TTokenType token) {
|
||||
if (service.OnAuthenticationFinished != null) {
|
||||
service.OnAuthenticationFinished.Invoke(token);
|
||||
}
|
||||
service = null;
|
||||
}
|
||||
|
||||
private void ExchangeTokenErrored(long code, string message) {
|
||||
UniWebViewLogger.Instance.Info("Auth flow errored: " + code + ". Detail: " + message);
|
||||
if (service.OnAuthenticationErrored != null) {
|
||||
service.OnAuthenticationErrored.Invoke(code, message);
|
||||
}
|
||||
service = null;
|
||||
}
|
||||
|
||||
private void RefreshTokenFinished(TTokenType token) {
|
||||
if (service.OnRefreshTokenFinished != null) {
|
||||
service.OnRefreshTokenFinished.Invoke(token);
|
||||
}
|
||||
service = null;
|
||||
}
|
||||
|
||||
private void RefreshTokenErrored(long code, string message) {
|
||||
UniWebViewLogger.Instance.Info("Refresh flow errored: " + code + ". Detail: " + message);
|
||||
if (service.OnRefreshTokenErrored != null) {
|
||||
service.OnRefreshTokenErrored.Invoke(code, message);
|
||||
}
|
||||
service = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The configuration object of an authentication flow. This defines the authentication entry points.
|
||||
/// </summary>
|
||||
public class UniWebViewAuthenticationConfiguration {
|
||||
internal readonly string authorizationEndpoint;
|
||||
internal readonly string tokenEndpoint;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new authentication configuration object with the given entry points.
|
||||
/// </summary>
|
||||
/// <param name="authorizationEndpoint">The entry point to navigate end user to for authentication.</param>
|
||||
/// <param name="tokenEndpoint">The entry point which is used to exchange the received code to a valid access token.</param>
|
||||
public UniWebViewAuthenticationConfiguration(string authorizationEndpoint, string tokenEndpoint) {
|
||||
this.authorizationEndpoint = authorizationEndpoint;
|
||||
this.tokenEndpoint = tokenEndpoint;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The exception thrown when the authentication flow fails when handling the response.
|
||||
/// </summary>
|
||||
public class AuthenticationResponseException : Exception {
|
||||
/// <summary>
|
||||
/// Exception error code to identify the error type. See the static instance of this class to know detail of error codes.
|
||||
/// </summary>
|
||||
public int Code { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates an authentication response exception.
|
||||
/// </summary>
|
||||
/// <param name="code">The error code.</param>
|
||||
/// <param name="message">A message that contains error detail.</param>
|
||||
public AuthenticationResponseException(int code, string message): base(message) {
|
||||
Code = code;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An unexpected authentication callback is received. Error code 7001.
|
||||
/// </summary>
|
||||
public static AuthenticationResponseException UnexpectedAuthCallbackUrl
|
||||
= new AuthenticationResponseException(7001, "The received callback url is not expected.");
|
||||
|
||||
/// <summary>
|
||||
/// The `state` value in the callback url is not the same as the one in the request. Error code 7002.
|
||||
/// </summary>
|
||||
public static AuthenticationResponseException InvalidState
|
||||
= new AuthenticationResponseException(7002, "The `state` is not valid.");
|
||||
|
||||
/// <summary>
|
||||
/// The response is not a valid one. It does not contains a `code` field or cannot be parsed. Error code 7003.
|
||||
/// </summary>
|
||||
/// <param name="query">The query will be delivered as a part of error message.</param>
|
||||
/// <returns>The created response exception that can be thrown out and handled by package user.</returns>
|
||||
public static AuthenticationResponseException InvalidResponse(string query) {
|
||||
return new AuthenticationResponseException(7003, "The service auth response is not valid: " + query);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4add539e6d306455c9da09b069e248bd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,235 @@
|
|||
//
|
||||
// UniWebViewAuthenticationFlowCustomize.cs
|
||||
// Created by Wang Wei (@onevcat) on 2022-06-25.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
/// <summary>
|
||||
/// A customizable authentication flow behavior.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Besides of the predefined authentication flows, such as Twitter (`UniWebViewAuthenticationFlowTwitter`) or Google
|
||||
/// (`UniWebViewAuthenticationFlowGoogle`), this class allows you to determine the details of the authentication flow,
|
||||
/// such as entry points, grant types, scopes and more. But similar to other target-specified flows, it follows the same
|
||||
/// OAuth 2.0 code auth pattern.
|
||||
///
|
||||
/// If you need to support other authentication flows for the platform targets other than the predefined ones, you can
|
||||
/// use this class and set all necessary parameters. It runs the standard OAuth 2.0 flow and gives out a
|
||||
/// `UniWebViewAuthenticationStandardToken` as the result.
|
||||
///
|
||||
/// If you need to support authentication flows other than `code` based OAuth 2.0, try to derive from
|
||||
/// `UniWebViewAuthenticationCommonFlow` and implement `IUniWebViewAuthenticationFlow` interface, or even use the
|
||||
/// underneath `UniWebViewAuthenticationSession` to get a highly customizable flow.
|
||||
///
|
||||
/// </remarks>
|
||||
public class UniWebViewAuthenticationFlowCustomize : UniWebViewAuthenticationCommonFlow, IUniWebViewAuthenticationFlow<UniWebViewAuthenticationStandardToken> {
|
||||
|
||||
/// <summary>
|
||||
/// The config object which defines the basic information of the authentication flow.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationFlowCustomizeConfig config = new UniWebViewAuthenticationFlowCustomizeConfig();
|
||||
|
||||
/// <summary>
|
||||
/// The client Id of your OAuth application.
|
||||
/// </summary>
|
||||
public string clientId = "";
|
||||
|
||||
/// <summary>
|
||||
/// The redirect URI of your OAuth application. The service provider is expected to call this URI to pass back the
|
||||
/// authorization code. It should be something also set to your OAuth application.
|
||||
///
|
||||
/// Also remember to add it to the "Auth Callback Urls" field in UniWebView's preference panel.
|
||||
/// </summary>
|
||||
public string redirectUri = "";
|
||||
|
||||
/// <summary>
|
||||
/// The scope of the authentication request.
|
||||
/// </summary>
|
||||
public string scope = "";
|
||||
|
||||
/// <summary>
|
||||
/// The optional object which defines some optional parameters of the authentication flow, such as whether supports
|
||||
/// `state` or `PKCE`.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationFlowCustomizeOptional optional;
|
||||
|
||||
/// <summary>
|
||||
/// Starts the authentication flow with the standard OAuth 2.0.
|
||||
/// This implements the abstract method in `UniWebViewAuthenticationCommonFlow`.
|
||||
/// </summary>
|
||||
public override void StartAuthenticationFlow() {
|
||||
var flow = new UniWebViewAuthenticationFlow<UniWebViewAuthenticationStandardToken>(this);
|
||||
flow.StartAuth();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the refresh flow with the standard OAuth 2.0.
|
||||
/// This implements the abstract method in `UniWebViewAuthenticationCommonFlow`.
|
||||
/// </summary>
|
||||
/// <param name="refreshToken">The refresh token received with a previous access token response.</param>
|
||||
public override void StartRefreshTokenFlow(string refreshToken) {
|
||||
var flow = new UniWebViewAuthenticationFlow<UniWebViewAuthenticationStandardToken>(this);
|
||||
flow.RefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public virtual UniWebViewAuthenticationConfiguration GetAuthenticationConfiguration() {
|
||||
return new UniWebViewAuthenticationConfiguration(
|
||||
config.authorizationEndpoint,
|
||||
config.tokenEndpoint
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public virtual string GetCallbackUrl() {
|
||||
return redirectUri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public virtual Dictionary<string, string> GetAuthenticationUriArguments() {
|
||||
var authorizeArgs = new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "redirect_uri", redirectUri },
|
||||
{ "scope", scope },
|
||||
{ "response_type", config.responseType }
|
||||
};
|
||||
if (optional != null) {
|
||||
if (optional.enableState) {
|
||||
var state = GenerateAndStoreState();
|
||||
authorizeArgs.Add("state", state);
|
||||
}
|
||||
|
||||
if (optional.PKCESupport != UniWebViewAuthenticationPKCE.None) {
|
||||
var codeChallenge = GenerateCodeChallengeAndStoreCodeVerify(optional.PKCESupport);
|
||||
authorizeArgs.Add("code_challenge", codeChallenge);
|
||||
|
||||
var method = UniWebViewAuthenticationUtils.ConvertPKCEToString(optional.PKCESupport);
|
||||
authorizeArgs.Add("code_challenge_method", method);
|
||||
}
|
||||
}
|
||||
|
||||
return authorizeArgs;
|
||||
}
|
||||
|
||||
public string GetAdditionalAuthenticationUriQuery() {
|
||||
return optional.additionalAuthenticationUriQuery;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public virtual Dictionary<string, string> GetAccessTokenRequestParameters(string authResponse) {
|
||||
if (!authResponse.StartsWith(redirectUri, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
throw AuthenticationResponseException.UnexpectedAuthCallbackUrl;
|
||||
}
|
||||
|
||||
var uri = new Uri(authResponse);
|
||||
var response = UniWebViewAuthenticationUtils.ParseFormUrlEncodedString(uri.Query);
|
||||
if (!response.TryGetValue("code", out var code)) {
|
||||
throw AuthenticationResponseException.InvalidResponse(authResponse);
|
||||
}
|
||||
if (optional != null && optional.enableState) {
|
||||
VerifyState(response);
|
||||
}
|
||||
var parameters = new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "code", code },
|
||||
{ "redirect_uri", redirectUri },
|
||||
{ "grant_type", config.grantType },
|
||||
};
|
||||
if (CodeVerify != null) {
|
||||
parameters.Add("code_verifier", CodeVerify);
|
||||
}
|
||||
if (optional != null && !String.IsNullOrEmpty(optional.clientSecret)) {
|
||||
parameters.Add("client_secret", optional.clientSecret);
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public virtual Dictionary<string, string> GetRefreshTokenRequestParameters(string refreshToken) {
|
||||
var parameters = new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "refresh_token", refreshToken },
|
||||
{ "grant_type", config.refreshTokenGrantType }
|
||||
};
|
||||
if (optional != null && !String.IsNullOrEmpty(optional.clientSecret)) {
|
||||
parameters.Add("client_secret", optional.clientSecret);
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public virtual UniWebViewAuthenticationStandardToken GenerateTokenFromExchangeResponse(string exchangeResponse) {
|
||||
return UniWebViewAuthenticationTokenFactory<UniWebViewAuthenticationStandardToken>.Parse(exchangeResponse);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<UniWebViewAuthenticationStandardToken> OnAuthenticationFinished { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<long, string> OnAuthenticationErrored { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<UniWebViewAuthenticationStandardToken> OnRefreshTokenFinished { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<long, string> OnRefreshTokenErrored { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class UniWebViewAuthenticationFlowCustomizeConfig {
|
||||
public string authorizationEndpoint = "";
|
||||
public string tokenEndpoint = "";
|
||||
public string responseType = "code";
|
||||
public string grantType = "authorization_code";
|
||||
|
||||
public string refreshTokenGrantType = "refresh_token";
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class UniWebViewAuthenticationFlowCustomizeOptional {
|
||||
public UniWebViewAuthenticationPKCE PKCESupport = UniWebViewAuthenticationPKCE.None;
|
||||
public bool enableState = false;
|
||||
public string clientSecret = "";
|
||||
public string additionalAuthenticationUriQuery = "";
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bfcc799dc1a0c4ef58bc3486a8af7afa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,236 @@
|
|||
//
|
||||
// UniWebViewAuthenticationFlowDiscord.cs
|
||||
// Created by Wang Wei (@onevcat) on 2022-06-25.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
/// <summary>
|
||||
/// A predefined authentication flow for Discord.
|
||||
///
|
||||
/// This implementation follows the flow described here:
|
||||
/// https://discord.com/developers/docs/topics/oauth2
|
||||
///
|
||||
/// See https://docs.uniwebview.com/guide/oauth2.html for a more detailed guide of authentication in UniWebView.
|
||||
/// </summary>
|
||||
public class UniWebViewAuthenticationFlowDiscord : UniWebViewAuthenticationCommonFlow, IUniWebViewAuthenticationFlow<UniWebViewAuthenticationDiscordToken> {
|
||||
/// <summary>
|
||||
/// The client ID of your Discord application.
|
||||
/// </summary>
|
||||
public string clientId = "";
|
||||
|
||||
/// <summary>
|
||||
/// The client secret of your Discord application.
|
||||
/// </summary>
|
||||
public string clientSecret = "";
|
||||
|
||||
/// <summary>
|
||||
/// The redirect URI of this Discord application.
|
||||
/// </summary>
|
||||
public string redirectUri = "";
|
||||
|
||||
/// <summary>
|
||||
/// The scope string of all your required scopes.
|
||||
/// </summary>
|
||||
public string scope = "";
|
||||
|
||||
/// <summary>
|
||||
/// Optional to control this flow's behaviour.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationFlowDiscordOptional optional;
|
||||
|
||||
private const string responseType = "code";
|
||||
private const string grantType = "authorization_code";
|
||||
|
||||
private readonly UniWebViewAuthenticationConfiguration config =
|
||||
new UniWebViewAuthenticationConfiguration(
|
||||
"https://discord.com/api/oauth2/authorize",
|
||||
"https://discord.com/api/oauth2/token"
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Starts the authentication flow with the standard OAuth 2.0.
|
||||
/// This implements the abstract method in `UniWebViewAuthenticationCommonFlow`.
|
||||
/// </summary>
|
||||
public override void StartAuthenticationFlow() {
|
||||
var flow = new UniWebViewAuthenticationFlow<UniWebViewAuthenticationDiscordToken>(this);
|
||||
flow.StartAuth();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the refresh flow with the standard OAuth 2.0.
|
||||
/// This implements the abstract method in `UniWebViewAuthenticationCommonFlow`.
|
||||
/// </summary>
|
||||
/// <param name="refreshToken">The refresh token received with a previous access token response.</param>
|
||||
public override void StartRefreshTokenFlow(string refreshToken) {
|
||||
var flow = new UniWebViewAuthenticationFlow<UniWebViewAuthenticationDiscordToken>(this);
|
||||
flow.RefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationConfiguration GetAuthenticationConfiguration() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public string GetCallbackUrl() {
|
||||
return redirectUri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetAuthenticationUriArguments() {
|
||||
var authorizeArgs = new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "redirect_uri", redirectUri },
|
||||
{ "scope", scope },
|
||||
{ "response_type", responseType }
|
||||
};
|
||||
if (optional != null) {
|
||||
if (optional.enableState) {
|
||||
var state = GenerateAndStoreState();
|
||||
authorizeArgs.Add("state", state);
|
||||
}
|
||||
|
||||
if (optional.PKCESupport != UniWebViewAuthenticationPKCE.None) {
|
||||
var codeChallenge = GenerateCodeChallengeAndStoreCodeVerify(optional.PKCESupport);
|
||||
authorizeArgs.Add("code_challenge", codeChallenge);
|
||||
|
||||
var method = UniWebViewAuthenticationUtils.ConvertPKCEToString(optional.PKCESupport);
|
||||
authorizeArgs.Add("code_challenge_method", method);
|
||||
}
|
||||
}
|
||||
|
||||
return authorizeArgs;
|
||||
}
|
||||
|
||||
public string GetAdditionalAuthenticationUriQuery() {
|
||||
return optional.additionalAuthenticationUriQuery;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetAccessTokenRequestParameters(string authResponse) {
|
||||
if (!authResponse.StartsWith(redirectUri, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
throw AuthenticationResponseException.UnexpectedAuthCallbackUrl;
|
||||
}
|
||||
|
||||
var uri = new Uri(authResponse);
|
||||
var response = UniWebViewAuthenticationUtils.ParseFormUrlEncodedString(uri.Query);
|
||||
if (!response.TryGetValue("code", out var code)) {
|
||||
throw AuthenticationResponseException.InvalidResponse(authResponse);
|
||||
}
|
||||
if (optional.enableState) {
|
||||
VerifyState(response);
|
||||
}
|
||||
var parameters = new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "client_secret", clientSecret },
|
||||
{ "code", code },
|
||||
{ "redirect_uri", redirectUri },
|
||||
{ "grant_type", grantType },
|
||||
};
|
||||
if (CodeVerify != null) {
|
||||
parameters.Add("code_verifier", CodeVerify);
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetRefreshTokenRequestParameters(string refreshToken) {
|
||||
return new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "client_secret", clientSecret },
|
||||
{ "refresh_token", refreshToken },
|
||||
{ "grant_type", "refresh_token" }
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationDiscordToken GenerateTokenFromExchangeResponse(string exchangeResponse) {
|
||||
return UniWebViewAuthenticationTokenFactory<UniWebViewAuthenticationDiscordToken>.Parse(exchangeResponse);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<UniWebViewAuthenticationDiscordToken> OnAuthenticationFinished { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<long, string> OnAuthenticationErrored { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<UniWebViewAuthenticationDiscordToken> OnRefreshTokenFinished { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<long, string> OnRefreshTokenErrored { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The authentication flow's optional settings for Discord.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class UniWebViewAuthenticationFlowDiscordOptional {
|
||||
/// <summary>
|
||||
/// Whether to enable PKCE when performing authentication. On mobile platforms, this has to be enabled as `S256`,
|
||||
/// otherwise, Discord will reject the authentication request.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationPKCE PKCESupport = UniWebViewAuthenticationPKCE.S256;
|
||||
/// <summary>
|
||||
/// Whether to enable the state verification. If enabled, the state will be generated and verified in the
|
||||
/// authentication callback. Default is `true`.
|
||||
/// </summary>
|
||||
public bool enableState = true;
|
||||
|
||||
/// <summary>
|
||||
/// The additional query arguments that are used to construct the query string of the authentication request.
|
||||
///
|
||||
/// This is useful when you want to add some custom parameters to the authentication request. This string will be
|
||||
/// appended to the query string that constructed from `GetAuthenticationUriArguments`.
|
||||
///
|
||||
/// For example, if you set `prompt=consent&ui_locales=en`, it will be contained in the final authentication query.
|
||||
/// </summary>
|
||||
public string additionalAuthenticationUriQuery = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The token object from Discord. Check `UniWebViewAuthenticationStandardToken` for more.
|
||||
/// </summary>
|
||||
public class UniWebViewAuthenticationDiscordToken : UniWebViewAuthenticationStandardToken { }
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 69ed5d1df2635470ca5c939d11d16924
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
//
|
||||
// UniWebViewAuthenticationFlowFacebook.cs
|
||||
// Created by Wang Wei (@onevcat) on 2022-06-25.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
/// <summary>
|
||||
/// A predefined authentication flow for Facebook Login.
|
||||
///
|
||||
/// It is not a standard OAuth2 flow, and using a plain web view. There once was a policy that Facebook did not allow
|
||||
/// any third-party customize authentication flow other than using their official SDK. Recently Facebook started to provide
|
||||
/// a so-called manual flow way to perform authentication. But it is originally only for Desktop apps, it is not stable
|
||||
/// and not standard.
|
||||
///
|
||||
/// Facebook suggests "For mobile apps, use the Facebook SDKs for iOS and Android, and follow the separate guides for
|
||||
/// these platforms." So on mobile, use this class with your own risk since it might be invalidated or forbidden by
|
||||
/// Facebook in the future.
|
||||
///
|
||||
/// This implementation is based on the manual flow described in the following document:
|
||||
/// https://developers.facebook.com/docs/facebook-login/guides/advanced/manual-flow
|
||||
///
|
||||
/// See https://docs.uniwebview.com/guide/oauth2.html for a more detailed guide of authentication in UniWebView.
|
||||
/// </summary>
|
||||
public class UniWebViewAuthenticationFlowFacebook: UniWebViewAuthenticationCommonFlow {
|
||||
/// <summary>
|
||||
/// The App ID of your Facebook application
|
||||
/// </summary>
|
||||
public string appId = "";
|
||||
|
||||
/// <summary>
|
||||
/// Optional to control this flow's behaviour.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationFlowFacebookOptional optional;
|
||||
|
||||
// The redirect URL should be exactly this one. Web view should inspect the loading of this URL to handle the result.
|
||||
private const string redirectUri = "https://www.facebook.com/connect/login_success.html";
|
||||
|
||||
// Only `token` response type is supported to use Facebook Login as the manual flow.
|
||||
private const string responseType = "token";
|
||||
|
||||
[field: SerializeField]
|
||||
public UnityEvent<UniWebViewAuthenticationFacebookToken> OnAuthenticationFinished { get; set; }
|
||||
[field: SerializeField]
|
||||
public UnityEvent<long, string> OnAuthenticationErrored { get; set; }
|
||||
|
||||
private readonly UniWebViewAuthenticationConfiguration config =
|
||||
new UniWebViewAuthenticationConfiguration(
|
||||
"https://www.facebook.com/v14.0/dialog/oauth",
|
||||
// This `access_token` entry point is in fact not used in current auth model.
|
||||
"https://graph.facebook.com/v14.0/oauth/access_token"
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Starts the authentication flow.
|
||||
///
|
||||
/// This flow is executed in a customized web view and it is not a standard OAuth2 flow.
|
||||
/// </summary>
|
||||
public override void StartAuthenticationFlow() {
|
||||
var webView = gameObject.AddComponent<UniWebView>();
|
||||
|
||||
// Facebook login deprecates the Web View login on Android. As a workaround, prevents to be a desktop browser to continue the manual flow.
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
webView.SetUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 13_0_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15");
|
||||
#endif
|
||||
|
||||
webView.OnPageFinished += (view, status, url) => {
|
||||
if (status != 200) {
|
||||
if (OnAuthenticationErrored != null) {
|
||||
OnAuthenticationErrored.Invoke(status, "Error while loading auth page.");
|
||||
}
|
||||
webView.Hide(false, UniWebViewTransitionEdge.Bottom, 0.25f, () => {
|
||||
Destroy(webView);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (url.StartsWith(redirectUri)) {
|
||||
UniWebViewLogger.Instance.Info("Received redirect url: " + url);
|
||||
var uri = new Uri(url);
|
||||
var response = UniWebViewAuthenticationUtils.ParseFormUrlEncodedString(uri.Fragment);
|
||||
try {
|
||||
VerifyState(response);
|
||||
var token = new UniWebViewAuthenticationFacebookToken(url, response);
|
||||
if (OnAuthenticationFinished != null) {
|
||||
OnAuthenticationFinished.Invoke(token);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
var message = e.Message;
|
||||
var code = -1;
|
||||
if (e is AuthenticationResponseException ex) {
|
||||
code = ex.Code;
|
||||
}
|
||||
|
||||
UniWebViewLogger.Instance.Critical("Exception on parsing response: " + e + ". Code: " + code +
|
||||
". Message: " + message);
|
||||
if (OnAuthenticationErrored != null) {
|
||||
OnAuthenticationErrored.Invoke(code, message);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
webView.Hide(false, UniWebViewTransitionEdge.Bottom, 0.25f, () => {
|
||||
Destroy(webView);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
webView.OnLoadingErrorReceived += (view, code, message, payload) => {
|
||||
if (OnAuthenticationErrored != null) {
|
||||
OnAuthenticationErrored.Invoke(code, message);
|
||||
}
|
||||
};
|
||||
webView.Frame = new Rect(0, 0, Screen.width, Screen.height);
|
||||
webView.Load(GetAuthUrl());
|
||||
webView.EmbeddedToolbar.Show();
|
||||
webView.Show(false, UniWebViewTransitionEdge.Bottom, 0.25f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the refresh flow with the standard OAuth 2.0.
|
||||
/// This implements the abstract method in `UniWebViewAuthenticationCommonFlow`.
|
||||
/// </summary>
|
||||
/// <param name="refreshToken">The refresh token received with a previous access token response.</param>
|
||||
public override void StartRefreshTokenFlow(string refreshToken) {
|
||||
Debug.LogError("Facebook does not provide a refresh token flow when building with the manual flow.");
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string GetAuthUrl() {
|
||||
var builder = new UriBuilder(config.authorizationEndpoint);
|
||||
var query = new Dictionary<string, string>();
|
||||
foreach (var kv in GetAuthenticationUriArguments()) {
|
||||
query.Add(kv.Key, kv.Value);
|
||||
}
|
||||
|
||||
builder.Query = UniWebViewAuthenticationUtils.CreateQueryString(query, optional.additionalAuthenticationUriQuery);
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private Dictionary<string, string> GetAuthenticationUriArguments() {
|
||||
|
||||
var state = GenerateAndStoreState();
|
||||
var authorizeArgs = new Dictionary<string, string> {
|
||||
{ "client_id", appId },
|
||||
{ "redirect_uri", redirectUri },
|
||||
{ "state", state},
|
||||
{ "response_type", responseType }
|
||||
};
|
||||
if (optional != null) {
|
||||
if (!String.IsNullOrEmpty(optional.scope)) {
|
||||
authorizeArgs.Add("scope", optional.scope);
|
||||
}
|
||||
}
|
||||
|
||||
return authorizeArgs;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The authentication flow's optional settings for Facebook.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class UniWebViewAuthenticationFlowFacebookOptional {
|
||||
/// <summary>
|
||||
/// The scope string of all your required scopes.
|
||||
/// </summary>
|
||||
public string scope = "";
|
||||
|
||||
/// <summary>
|
||||
/// The additional query arguments that are used to construct the query string of the authentication request.
|
||||
///
|
||||
/// This is useful when you want to add some custom parameters to the authentication request. This string will be
|
||||
/// appended to the query string that constructed from `GetAuthenticationUriArguments`.
|
||||
///
|
||||
/// For example, if you set `prompt=consent&ui_locales=en`, it will be contained in the final authentication query.
|
||||
/// </summary>
|
||||
public string additionalAuthenticationUriQuery = "";
|
||||
}
|
||||
|
||||
/// The token object from Facebook.
|
||||
public class UniWebViewAuthenticationFacebookToken {
|
||||
/// <summary>
|
||||
/// The access token received from Facebook Login.
|
||||
/// </summary>
|
||||
public string AccessToken { get; }
|
||||
/// <summary>
|
||||
/// The expiration duration that your app can access requested items of user data.
|
||||
/// </summary>
|
||||
public long DataAccessExpirationTime { get; }
|
||||
/// <summary>
|
||||
/// The expiration duration that the access token is valid for authentication purpose.
|
||||
/// </summary>
|
||||
public long ExpiresIn { get; }
|
||||
/// <summary>
|
||||
/// The raw value of the response of the exchange token request.
|
||||
/// If the predefined fields are not enough, you can parse the raw value to get the extra information.
|
||||
/// </summary>
|
||||
public string RawValue { get; }
|
||||
|
||||
public UniWebViewAuthenticationFacebookToken(string response, Dictionary<string, string> values) {
|
||||
RawValue = response;
|
||||
AccessToken = values.ContainsKey("access_token") ? values["access_token"] : null ;
|
||||
if (AccessToken == null) {
|
||||
throw AuthenticationResponseException.InvalidResponse(response);
|
||||
}
|
||||
DataAccessExpirationTime = values.ContainsKey("data_access_expiration_time") ? long.Parse(values["data_access_expiration_time"]) : 0;
|
||||
ExpiresIn = values.ContainsKey("expires_in") ? long.Parse(values["expires_in"]) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ba2d51a8adc8e42b4aaff50218dfe058
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,280 @@
|
|||
//
|
||||
// UniWebViewAuthenticationFlowGitHub.cs
|
||||
// Created by Wang Wei (@onevcat) on 2022-06-25.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// A predefined authentication flow for GitHub.
|
||||
///
|
||||
/// This implementation follows the flow described here:
|
||||
/// https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps
|
||||
///
|
||||
/// See https://docs.uniwebview.com/guide/oauth2.html for a more detailed guide of authentication in UniWebView.
|
||||
/// </summary>
|
||||
public class UniWebViewAuthenticationFlowGitHub: UniWebViewAuthenticationCommonFlow, IUniWebViewAuthenticationFlow<UniWebViewAuthenticationGitHubToken> {
|
||||
|
||||
/// <summary>
|
||||
/// The client ID of your GitHub application.
|
||||
/// </summary>
|
||||
public string clientId = "";
|
||||
|
||||
/// <summary>
|
||||
/// The client secret of your GitHub application.
|
||||
/// </summary>
|
||||
public string clientSecret = "";
|
||||
|
||||
/// <summary>
|
||||
/// The callback URL of your GitHub application.
|
||||
/// </summary>
|
||||
public string callbackUrl = "";
|
||||
|
||||
/// <summary>
|
||||
/// Optional to control this flow's behaviour.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationFlowGitHubOptional optional;
|
||||
|
||||
private readonly UniWebViewAuthenticationConfiguration config =
|
||||
new UniWebViewAuthenticationConfiguration(
|
||||
"https://github.com/login/oauth/authorize",
|
||||
"https://github.com/login/oauth/access_token"
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<UniWebViewAuthenticationGitHubToken> OnAuthenticationFinished { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<long, string> OnAuthenticationErrored { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<UniWebViewAuthenticationGitHubToken> OnRefreshTokenFinished { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<long, string> OnRefreshTokenErrored { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Starts the authentication flow with the standard OAuth 2.0.
|
||||
/// This implements the abstract method in `UniWebViewAuthenticationCommonFlow`.
|
||||
/// </summary>
|
||||
public override void StartAuthenticationFlow() {
|
||||
var flow = new UniWebViewAuthenticationFlow<UniWebViewAuthenticationGitHubToken>(this);
|
||||
flow.StartAuth();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the refresh flow with the standard OAuth 2.0.
|
||||
/// This implements the abstract method in `UniWebViewAuthenticationCommonFlow`.
|
||||
/// </summary>
|
||||
/// <param name="refreshToken">The refresh token received with a previous access token response.</param>
|
||||
public override void StartRefreshTokenFlow(string refreshToken) {
|
||||
var flow = new UniWebViewAuthenticationFlow<UniWebViewAuthenticationGitHubToken>(this);
|
||||
flow.RefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetAuthenticationUriArguments() {
|
||||
var authorizeArgs = new Dictionary<string, string> { { "client_id", clientId } };
|
||||
if (optional != null) {
|
||||
if (!String.IsNullOrEmpty(optional.redirectUri)) {
|
||||
authorizeArgs.Add("redirect_uri", optional.redirectUri);
|
||||
}
|
||||
if (!String.IsNullOrEmpty(optional.login)) {
|
||||
authorizeArgs.Add("login", optional.login);
|
||||
}
|
||||
if (!String.IsNullOrEmpty(optional.scope)) {
|
||||
authorizeArgs.Add("scope", optional.scope);
|
||||
}
|
||||
if (optional.enableState) {
|
||||
var state = GenerateAndStoreState();
|
||||
authorizeArgs.Add("state", state);
|
||||
}
|
||||
if (!optional.allowSignup) { // The default value is true.
|
||||
authorizeArgs.Add("allow_signup", "false");
|
||||
}
|
||||
if (!String.IsNullOrEmpty(optional.prompt)) {
|
||||
authorizeArgs.Add("prompt", optional.prompt);
|
||||
}
|
||||
}
|
||||
|
||||
return authorizeArgs;
|
||||
}
|
||||
|
||||
public string GetAdditionalAuthenticationUriQuery() {
|
||||
return optional.additionalAuthenticationUriQuery;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public string GetCallbackUrl() {
|
||||
return callbackUrl;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationConfiguration GetAuthenticationConfiguration() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetAccessTokenRequestParameters(string authResponse) {
|
||||
if (!authResponse.StartsWith(callbackUrl, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
throw AuthenticationResponseException.UnexpectedAuthCallbackUrl;
|
||||
}
|
||||
var uri = new Uri(authResponse);
|
||||
var response = UniWebViewAuthenticationUtils.ParseFormUrlEncodedString(uri.Query);
|
||||
if (!response.TryGetValue("code", out var code)) {
|
||||
throw AuthenticationResponseException.InvalidResponse(authResponse);
|
||||
}
|
||||
if (optional.enableState) {
|
||||
VerifyState(response);
|
||||
}
|
||||
var result = new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "client_secret", clientSecret },
|
||||
{ "code", code }
|
||||
};
|
||||
|
||||
if (optional != null && String.IsNullOrEmpty(optional.redirectUri)) {
|
||||
result.Add("redirect_uri", optional.redirectUri);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetRefreshTokenRequestParameters(string refreshToken) {
|
||||
return new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "client_secret", clientSecret },
|
||||
{ "refresh_token", refreshToken },
|
||||
{ "grant_type", "refresh_token" }
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationGitHubToken GenerateTokenFromExchangeResponse(string exchangeResponse) {
|
||||
return new UniWebViewAuthenticationGitHubToken(exchangeResponse);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The authentication flow's optional settings for GitHub.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class UniWebViewAuthenticationFlowGitHubOptional {
|
||||
/// <summary>
|
||||
/// The redirect URI should be used in exchange token request.
|
||||
/// </summary>
|
||||
public string redirectUri = "";
|
||||
/// <summary>
|
||||
/// Suggests a specific account to use for signing in and authorizing the app.
|
||||
/// </summary>
|
||||
public string login = "";
|
||||
/// <summary>
|
||||
/// The scope string of all your required scopes.
|
||||
/// </summary>
|
||||
public string scope = "";
|
||||
/// <summary>
|
||||
/// Whether to enable the state verification. If enabled, the state will be generated and verified in the
|
||||
/// authentication callback.
|
||||
/// </summary>
|
||||
public bool enableState = false;
|
||||
/// <summary>
|
||||
/// Whether unauthenticated users will be offered an option to sign up for GitHub during the OAuth flow.
|
||||
/// </summary>
|
||||
public bool allowSignup = true;
|
||||
|
||||
/// <summary>
|
||||
/// The prompt that will be set to the authentication request query. For example, the possible values can be
|
||||
/// `login`, `consent`, `select_account` and so on.
|
||||
///
|
||||
/// See https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
|
||||
/// </summary>
|
||||
public string prompt = "";
|
||||
|
||||
/// <summary>
|
||||
/// The additional query arguments that are used to construct the query string of the authentication request.
|
||||
///
|
||||
/// This is useful when you want to add some custom parameters to the authentication request. This string will be
|
||||
/// appended to the query string that constructed from `GetAuthenticationUriArguments`.
|
||||
///
|
||||
/// For example, if you set `prompt=consent&ui_locales=en`, it will be contained in the final authentication query.
|
||||
/// </summary>
|
||||
public string additionalAuthenticationUriQuery = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The token object from GitHub.
|
||||
/// </summary>
|
||||
public class UniWebViewAuthenticationGitHubToken {
|
||||
/// <summary>The access token retrieved from the service provider.</summary>
|
||||
public string AccessToken { get; }
|
||||
|
||||
/// <summary>The granted scopes of the token.</summary>
|
||||
public string Scope { get; }
|
||||
|
||||
/// <summary>The token type. Usually `bearer`.</summary>
|
||||
public string TokenType { get; }
|
||||
|
||||
/// <summary>The refresh token retrieved from the service provider.</summary>
|
||||
public string RefreshToken { get; }
|
||||
|
||||
/// <summary>Expiration duration for the refresh token.</summary>
|
||||
public long RefreshTokenExpiresIn { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The raw value of the response of the exchange token request.
|
||||
/// If the predefined fields are not enough, you can parse the raw value to get the extra information.
|
||||
/// </summary>
|
||||
public string RawValue { get; }
|
||||
|
||||
public UniWebViewAuthenticationGitHubToken(string result) {
|
||||
RawValue = result;
|
||||
var values = UniWebViewAuthenticationUtils.ParseFormUrlEncodedString(result);
|
||||
AccessToken = values.ContainsKey("access_token") ? values["access_token"] : null ;
|
||||
if (AccessToken == null) {
|
||||
throw AuthenticationResponseException.InvalidResponse(result);
|
||||
}
|
||||
Scope = values.ContainsKey("scope") ? values["scope"] : null;
|
||||
TokenType = values.ContainsKey("token_type") ? values["token_type"] : null;
|
||||
RefreshToken = values.ContainsKey("refresh_token") ? values["refresh_token"] : null;
|
||||
RefreshTokenExpiresIn = values.ContainsKey("refresh_token_expires_in") ? long.Parse(values["refresh_token_expires_in"]) : 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1925cdd8b9d284ec48146d7d03c41672
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
//
|
||||
// UniWebViewAuthenticationFlowGoogle.cs
|
||||
// Created by Wang Wei (@onevcat) on 2022-06-25.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
/// <summary>
|
||||
/// A predefined authentication flow for Google Identity.
|
||||
///
|
||||
/// This implementation follows the flow described here:
|
||||
/// https://developers.google.com/identity/protocols/oauth2/native-app
|
||||
///
|
||||
/// Google authentication flow is a bit different from the other standard authentication flows. Please read the link
|
||||
/// above carefully to understand it.
|
||||
///
|
||||
/// See https://docs.uniwebview.com/guide/oauth2.html for a more detailed guide of authentication in UniWebView.
|
||||
/// </summary>
|
||||
public class UniWebViewAuthenticationFlowGoogle : UniWebViewAuthenticationCommonFlow, IUniWebViewAuthenticationFlow<UniWebViewAuthenticationGoogleToken> {
|
||||
/// <summary>
|
||||
/// The client ID of your Google application.
|
||||
/// </summary>
|
||||
public string clientId = "";
|
||||
|
||||
/// <summary>
|
||||
/// The redirect URI of your Google application.
|
||||
///
|
||||
/// It might be something like "com.googleusercontent.apps.${clientId}:${redirect_uri_path}". Be caution that the URI does not
|
||||
/// contain regular double slashes `//`, but should be only one.
|
||||
/// </summary>
|
||||
public string redirectUri = "";
|
||||
|
||||
/// <summary>
|
||||
/// The scope of your Google application.
|
||||
///
|
||||
/// It might be some full URL in recent Google services, such as "https://www.googleapis.com/auth/userinfo.profile"
|
||||
/// </summary>
|
||||
public string scope = "";
|
||||
|
||||
/// <summary>
|
||||
/// Optional to control this flow's behaviour.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationFlowGoogleOptional optional;
|
||||
|
||||
private const string responseType = "code";
|
||||
private const string grantType = "authorization_code";
|
||||
|
||||
private readonly UniWebViewAuthenticationConfiguration config =
|
||||
new UniWebViewAuthenticationConfiguration(
|
||||
"https://accounts.google.com/o/oauth2/v2/auth",
|
||||
"https://oauth2.googleapis.com/token"
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Starts the authentication flow with the standard OAuth 2.0.
|
||||
/// This implements the abstract method in `UniWebViewAuthenticationCommonFlow`.
|
||||
/// </summary>
|
||||
public override void StartAuthenticationFlow() {
|
||||
var flow = new UniWebViewAuthenticationFlow<UniWebViewAuthenticationGoogleToken>(this);
|
||||
flow.StartAuth();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the refresh flow with the standard OAuth 2.0.
|
||||
/// This implements the abstract method in `UniWebViewAuthenticationCommonFlow`.
|
||||
/// </summary>
|
||||
/// <param name="refreshToken">The refresh token received with a previous access token response.</param>
|
||||
public override void StartRefreshTokenFlow(string refreshToken) {
|
||||
var flow = new UniWebViewAuthenticationFlow<UniWebViewAuthenticationGoogleToken>(this);
|
||||
flow.RefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationConfiguration GetAuthenticationConfiguration() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public string GetCallbackUrl() {
|
||||
return redirectUri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetAuthenticationUriArguments() {
|
||||
var authorizeArgs = new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "redirect_uri", redirectUri },
|
||||
{ "scope", scope },
|
||||
{ "response_type", responseType }
|
||||
};
|
||||
if (optional != null) {
|
||||
if (optional.enableState) {
|
||||
var state = GenerateAndStoreState();
|
||||
authorizeArgs.Add("state", state);
|
||||
}
|
||||
|
||||
if (optional.PKCESupport != UniWebViewAuthenticationPKCE.None) {
|
||||
var codeChallenge = GenerateCodeChallengeAndStoreCodeVerify(optional.PKCESupport);
|
||||
authorizeArgs.Add("code_challenge", codeChallenge);
|
||||
|
||||
var method = UniWebViewAuthenticationUtils.ConvertPKCEToString(optional.PKCESupport);
|
||||
authorizeArgs.Add("code_challenge_method", method);
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(optional.loginHint)) {
|
||||
authorizeArgs.Add("login_hint", optional.loginHint);
|
||||
}
|
||||
if (!String.IsNullOrEmpty(optional.prompt)) {
|
||||
authorizeArgs.Add("prompt", optional.prompt);
|
||||
}
|
||||
}
|
||||
|
||||
return authorizeArgs;
|
||||
}
|
||||
|
||||
public string GetAdditionalAuthenticationUriQuery() {
|
||||
return optional.additionalAuthenticationUriQuery;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetAccessTokenRequestParameters(string authResponse) {
|
||||
if (!authResponse.StartsWith(redirectUri, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
throw AuthenticationResponseException.UnexpectedAuthCallbackUrl;
|
||||
}
|
||||
|
||||
var uri = new Uri(authResponse);
|
||||
var response = UniWebViewAuthenticationUtils.ParseFormUrlEncodedString(uri.Query);
|
||||
if (!response.TryGetValue("code", out var code)) {
|
||||
throw AuthenticationResponseException.InvalidResponse(authResponse);
|
||||
}
|
||||
if (optional.enableState) {
|
||||
VerifyState(response);
|
||||
}
|
||||
var parameters = new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "code", code },
|
||||
{ "redirect_uri", redirectUri },
|
||||
{ "grant_type", grantType },
|
||||
};
|
||||
if (CodeVerify != null) {
|
||||
parameters.Add("code_verifier", CodeVerify);
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetRefreshTokenRequestParameters(string refreshToken) {
|
||||
return new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "refresh_token", refreshToken },
|
||||
{ "grant_type", "refresh_token" }
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationGoogleToken GenerateTokenFromExchangeResponse(string exchangeResponse) {
|
||||
return UniWebViewAuthenticationTokenFactory<UniWebViewAuthenticationGoogleToken>.Parse(exchangeResponse);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<UniWebViewAuthenticationGoogleToken> OnAuthenticationFinished { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<long, string> OnAuthenticationErrored { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<UniWebViewAuthenticationGoogleToken> OnRefreshTokenFinished { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<long, string> OnRefreshTokenErrored { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The authentication flow's optional settings for Google.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class UniWebViewAuthenticationFlowGoogleOptional {
|
||||
/// <summary>
|
||||
/// Whether to enable PKCE when performing authentication. Default is `S256`.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationPKCE PKCESupport = UniWebViewAuthenticationPKCE.S256;
|
||||
/// <summary>
|
||||
/// Whether to enable the state verification. If enabled, the state will be generated and verified in the
|
||||
/// authentication callback. Default is `true`.
|
||||
/// </summary>
|
||||
public bool enableState = true;
|
||||
/// <summary>
|
||||
/// If your application knows which user is trying to authenticate, it can use this parameter to provide a hint to
|
||||
/// the Google Authentication Server.
|
||||
/// </summary>
|
||||
public string loginHint = "";
|
||||
|
||||
/// <summary>
|
||||
/// The prompt that will be set to the authentication request query. For example, the possible values can be
|
||||
/// `login`, `consent`, `select_account` and so on.
|
||||
///
|
||||
/// See https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
|
||||
/// </summary>
|
||||
public string prompt = "";
|
||||
|
||||
/// <summary>
|
||||
/// The additional query arguments that are used to construct the query string of the authentication request.
|
||||
///
|
||||
/// This is useful when you want to add some custom parameters to the authentication request. This string will be
|
||||
/// appended to the query string that constructed from `GetAuthenticationUriArguments`.
|
||||
///
|
||||
/// For example, if you set `prompt=consent&ui_locales=en`, it will be contained in the final authentication query.
|
||||
/// </summary>
|
||||
public string additionalAuthenticationUriQuery = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The token object from Google. Check `UniWebViewAuthenticationStandardToken` for more.
|
||||
/// </summary>
|
||||
public class UniWebViewAuthenticationGoogleToken : UniWebViewAuthenticationStandardToken { }
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9a51fd6394dc49ed954d995b9f7b0bbc
|
||||
timeCreated: 1655992593
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
//
|
||||
// UniWebViewAuthenticationFlowLine.cs
|
||||
// Created by Wang Wei (@onevcat) on 2022-06-25.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
/// <summary>
|
||||
/// A predefined authentication flow LINE Login.
|
||||
///
|
||||
/// This implementation follows the flow described here:
|
||||
/// https://developers.line.biz/en/reference/line-login/
|
||||
///
|
||||
/// Google authentication flow is a bit different from the other standard authentication flows. Please read the link
|
||||
/// above carefully to understand it.
|
||||
///
|
||||
/// See https://docs.uniwebview.com/guide/oauth2.html for a more detailed guide of authentication in UniWebView.
|
||||
/// </summary>
|
||||
public class UniWebViewAuthenticationFlowLine : UniWebViewAuthenticationCommonFlow, IUniWebViewAuthenticationFlow<UniWebViewAuthenticationLineToken> {
|
||||
/// <summary>
|
||||
/// The client ID (Channel ID) of your LINE Login application.
|
||||
/// </summary>
|
||||
public string clientId = "";
|
||||
|
||||
/// <summary>
|
||||
/// The iOS bundle Id you set in LINE developer console.
|
||||
/// </summary>
|
||||
public string iOSBundleId = "";
|
||||
|
||||
/// <summary>
|
||||
/// The Android package name you set in LINE developer console.
|
||||
/// </summary>
|
||||
public string androidPackageName = "";
|
||||
|
||||
/// <summary>
|
||||
/// The scope of your LINE application.
|
||||
/// </summary>
|
||||
public string scope = "";
|
||||
|
||||
/// <summary>
|
||||
/// Optional to control this flow's behaviour.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationFlowLineOptional optional;
|
||||
|
||||
private const string responseType = "code";
|
||||
private const string grantType = "authorization_code";
|
||||
|
||||
private string RedirectUri {
|
||||
get {
|
||||
if (Application.platform == RuntimePlatform.IPhonePlayer || Application.platform == RuntimePlatform.OSXEditor) {
|
||||
return $"line3rdp.{iOSBundleId}://auth";
|
||||
}
|
||||
|
||||
if (Application.platform == RuntimePlatform.Android) {
|
||||
return "intent://auth#Intent;package=" + androidPackageName + ";scheme=lineauth;end";
|
||||
}
|
||||
UniWebViewLogger.Instance.Critical("Not supported platform for LINE Login.");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private readonly UniWebViewAuthenticationConfiguration config =
|
||||
new UniWebViewAuthenticationConfiguration(
|
||||
"https://access.line.me/oauth2/v2.1/login",
|
||||
"https://api.line.me/oauth2/v2.1/token"
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Starts the authentication flow with the standard OAuth 2.0.
|
||||
/// This implements the abstract method in `UniWebViewAuthenticationCommonFlow`.
|
||||
/// </summary>
|
||||
public override void StartAuthenticationFlow() {
|
||||
var flow = new UniWebViewAuthenticationFlow<UniWebViewAuthenticationLineToken>(this);
|
||||
flow.StartAuth();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the refresh flow with the standard OAuth 2.0.
|
||||
/// This implements the abstract method in `UniWebViewAuthenticationCommonFlow`.
|
||||
/// </summary>
|
||||
/// <param name="refreshToken">The refresh token received with a previous access token response.</param>
|
||||
public override void StartRefreshTokenFlow(string refreshToken) {
|
||||
var flow = new UniWebViewAuthenticationFlow<UniWebViewAuthenticationLineToken>(this);
|
||||
flow.RefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationConfiguration GetAuthenticationConfiguration() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public string GetCallbackUrl() {
|
||||
return RedirectUri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetAuthenticationUriArguments() {
|
||||
var authorizeArgs = new Dictionary<string, string> {
|
||||
{ "loginChannelId", clientId },
|
||||
{ "returnUri", GenerateReturnUri() },
|
||||
};
|
||||
|
||||
return authorizeArgs;
|
||||
}
|
||||
|
||||
public string GetAdditionalAuthenticationUriQuery() {
|
||||
return optional.additionalAuthenticationUriQuery;
|
||||
}
|
||||
|
||||
private string GenerateReturnUri() {
|
||||
var query = new Dictionary<string, string> {
|
||||
{ "response_type", responseType },
|
||||
{ "client_id", clientId },
|
||||
{ "redirect_uri", RedirectUri }
|
||||
};
|
||||
|
||||
// State is a must in LINE Login.
|
||||
var state = GenerateAndStoreState();
|
||||
query.Add("state", state);
|
||||
|
||||
if (!String.IsNullOrEmpty(scope)) {
|
||||
query.Add("scope", scope);
|
||||
} else {
|
||||
query.Add("scope", "profile");
|
||||
}
|
||||
if (optional != null) {
|
||||
if (optional.PKCESupport != UniWebViewAuthenticationPKCE.None) {
|
||||
var codeChallenge = GenerateCodeChallengeAndStoreCodeVerify(optional.PKCESupport);
|
||||
query.Add("code_challenge", codeChallenge);
|
||||
|
||||
var method = UniWebViewAuthenticationUtils.ConvertPKCEToString(optional.PKCESupport);
|
||||
query.Add("code_challenge_method", method);
|
||||
}
|
||||
}
|
||||
var additionalQuery = GetAdditionalAuthenticationUriQuery();
|
||||
return "/oauth2/v2.1/authorize/consent?" + UniWebViewAuthenticationUtils.CreateQueryString(query, additionalQuery);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetAccessTokenRequestParameters(string authResponse) {
|
||||
var normalizedRedirectUri = UniWebViewAuthenticationUtils.ConvertIntentUri(RedirectUri);
|
||||
if (!authResponse.StartsWith(normalizedRedirectUri, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
throw AuthenticationResponseException.UnexpectedAuthCallbackUrl;
|
||||
}
|
||||
|
||||
var uri = new Uri(authResponse);
|
||||
var response = UniWebViewAuthenticationUtils.ParseFormUrlEncodedString(uri.Query);
|
||||
VerifyState(response);
|
||||
if (!response.TryGetValue("code", out var code)) {
|
||||
throw AuthenticationResponseException.InvalidResponse(authResponse);
|
||||
}
|
||||
var parameters = new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "code", code },
|
||||
{ "redirect_uri", RedirectUri },
|
||||
{ "grant_type", grantType },
|
||||
};
|
||||
if (CodeVerify != null) {
|
||||
parameters.Add("code_verifier", CodeVerify);
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetRefreshTokenRequestParameters(string refreshToken) {
|
||||
return new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "refresh_token", refreshToken },
|
||||
{ "grant_type", "refresh_token" }
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationLineToken GenerateTokenFromExchangeResponse(string exchangeResponse) {
|
||||
return UniWebViewAuthenticationTokenFactory<UniWebViewAuthenticationLineToken>.Parse(exchangeResponse);
|
||||
}
|
||||
|
||||
[field: SerializeField]
|
||||
public UnityEvent<UniWebViewAuthenticationLineToken> OnAuthenticationFinished { get; set; }
|
||||
[field: SerializeField]
|
||||
public UnityEvent<long, string> OnAuthenticationErrored { get; set; }
|
||||
[field: SerializeField]
|
||||
public UnityEvent<UniWebViewAuthenticationLineToken> OnRefreshTokenFinished { get; set; }
|
||||
[field: SerializeField]
|
||||
public UnityEvent<long, string> OnRefreshTokenErrored { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The authentication flow's optional settings for LINE.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class UniWebViewAuthenticationFlowLineOptional {
|
||||
/// <summary>
|
||||
/// Whether to enable PKCE when performing authentication. Default is `S256`.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationPKCE PKCESupport = UniWebViewAuthenticationPKCE.S256;
|
||||
|
||||
/// <summary>
|
||||
/// The additional query arguments that are used to construct the query string of the authentication request.
|
||||
///
|
||||
/// This is useful when you want to add some custom parameters to the authentication request. This string will be
|
||||
/// appended to the query string that constructed from `GetAuthenticationUriArguments`.
|
||||
///
|
||||
/// For example, if you set `prompt=consent&ui_locales=en`, it will be contained in the final authentication query.
|
||||
/// </summary>
|
||||
public string additionalAuthenticationUriQuery = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The token object from LINE. Check `UniWebViewAuthenticationStandardToken` for more.
|
||||
/// </summary>
|
||||
public class UniWebViewAuthenticationLineToken : UniWebViewAuthenticationStandardToken { }
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 69f3e0ea73db84403850bcdbc6531a62
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
//
|
||||
// UniWebViewAuthenticationFlowTwitter.cs
|
||||
// Created by Wang Wei (@onevcat) on 2022-06-25.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
/// <summary>
|
||||
/// A predefined authentication flow for Twitter.
|
||||
///
|
||||
/// This implementation follows the flow described here:
|
||||
/// https://developer.twitter.com/en/docs/authentication/oauth-2-0/authorization-code
|
||||
///
|
||||
/// See https://docs.uniwebview.com/guide/oauth2.html for a more detailed guide of authentication in UniWebView.
|
||||
/// </summary>
|
||||
public class UniWebViewAuthenticationFlowTwitter : UniWebViewAuthenticationCommonFlow, IUniWebViewAuthenticationFlow<UniWebViewAuthenticationTwitterToken> {
|
||||
/// <summary>
|
||||
/// The client ID of your Twitter application.
|
||||
/// </summary>
|
||||
public string clientId = "";
|
||||
/// <summary>
|
||||
/// The redirect URI of your Twitter application.
|
||||
/// </summary>
|
||||
public string redirectUri = "";
|
||||
/// <summary>
|
||||
/// The scope string of all your required scopes.
|
||||
/// </summary>
|
||||
public string scope = "";
|
||||
/// <summary>
|
||||
/// Optional to control this flow's behaviour.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationFlowTwitterOptional optional;
|
||||
|
||||
private const string responseType = "code";
|
||||
private const string grantType = "authorization_code";
|
||||
|
||||
private readonly UniWebViewAuthenticationConfiguration config =
|
||||
new UniWebViewAuthenticationConfiguration(
|
||||
"https://twitter.com/i/oauth2/authorize",
|
||||
"https://api.twitter.com/2/oauth2/token"
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Starts the authentication flow with the standard OAuth 2.0.
|
||||
/// This implements the abstract method in `UniWebViewAuthenticationCommonFlow`.
|
||||
/// </summary>
|
||||
public override void StartAuthenticationFlow() {
|
||||
var flow = new UniWebViewAuthenticationFlow<UniWebViewAuthenticationTwitterToken>(this);
|
||||
flow.StartAuth();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the refresh flow with the standard OAuth 2.0.
|
||||
/// This implements the abstract method in `UniWebViewAuthenticationCommonFlow`.
|
||||
/// </summary>
|
||||
/// <param name="refreshToken">The refresh token received with a previous access token response.</param>
|
||||
public override void StartRefreshTokenFlow(string refreshToken) {
|
||||
var flow = new UniWebViewAuthenticationFlow<UniWebViewAuthenticationTwitterToken>(this);
|
||||
flow.RefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationConfiguration GetAuthenticationConfiguration() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public string GetCallbackUrl() {
|
||||
return redirectUri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetAuthenticationUriArguments() {
|
||||
var authorizeArgs = new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "redirect_uri", redirectUri },
|
||||
{ "scope", scope },
|
||||
{ "response_type", responseType }
|
||||
};
|
||||
if (optional != null) {
|
||||
if (optional.enableState) {
|
||||
var state = GenerateAndStoreState();
|
||||
authorizeArgs.Add("state", state);
|
||||
}
|
||||
|
||||
if (optional.PKCESupport != UniWebViewAuthenticationPKCE.None) {
|
||||
var codeChallenge = GenerateCodeChallengeAndStoreCodeVerify(optional.PKCESupport);
|
||||
authorizeArgs.Add("code_challenge", codeChallenge);
|
||||
|
||||
var method = UniWebViewAuthenticationUtils.ConvertPKCEToString(optional.PKCESupport);
|
||||
authorizeArgs.Add("code_challenge_method", method);
|
||||
}
|
||||
}
|
||||
|
||||
return authorizeArgs;
|
||||
}
|
||||
|
||||
public string GetAdditionalAuthenticationUriQuery() {
|
||||
return optional.additionalAuthenticationUriQuery;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetAccessTokenRequestParameters(string authResponse) {
|
||||
if (!authResponse.StartsWith(redirectUri, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
throw AuthenticationResponseException.UnexpectedAuthCallbackUrl;
|
||||
}
|
||||
|
||||
var uri = new Uri(authResponse);
|
||||
var response = UniWebViewAuthenticationUtils.ParseFormUrlEncodedString(uri.Query);
|
||||
if (!response.TryGetValue("code", out var code)) {
|
||||
throw AuthenticationResponseException.InvalidResponse(authResponse);
|
||||
}
|
||||
if (optional.enableState) {
|
||||
VerifyState(response);
|
||||
}
|
||||
var parameters = new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "code", code },
|
||||
{ "redirect_uri", redirectUri },
|
||||
{ "grant_type", grantType },
|
||||
};
|
||||
if (CodeVerify != null) {
|
||||
parameters.Add("code_verifier", CodeVerify);
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GetRefreshTokenRequestParameters(string refreshToken) {
|
||||
return new Dictionary<string, string> {
|
||||
{ "client_id", clientId },
|
||||
{ "refresh_token", refreshToken },
|
||||
{ "grant_type", "refresh_token" }
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationTwitterToken GenerateTokenFromExchangeResponse(string exchangeResponse) {
|
||||
return UniWebViewAuthenticationTokenFactory<UniWebViewAuthenticationTwitterToken>.Parse(exchangeResponse);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<UniWebViewAuthenticationTwitterToken> OnAuthenticationFinished { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<long, string> OnAuthenticationErrored { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<UniWebViewAuthenticationTwitterToken> OnRefreshTokenFinished { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implements required method in `IUniWebViewAuthenticationFlow`.
|
||||
/// </summary>
|
||||
[field: SerializeField]
|
||||
public UnityEvent<long, string> OnRefreshTokenErrored { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The authentication flow's optional settings for Twitter.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class UniWebViewAuthenticationFlowTwitterOptional {
|
||||
/// <summary>
|
||||
/// Whether to enable PKCE when performing authentication.This has to be enabled as `S256`,
|
||||
/// otherwise, Twitter will reject the authentication request.
|
||||
/// </summary>
|
||||
public UniWebViewAuthenticationPKCE PKCESupport = UniWebViewAuthenticationPKCE.S256;
|
||||
/// <summary>
|
||||
/// Whether to enable the state verification. If enabled, the state will be generated and verified in the
|
||||
/// authentication callback. This has to be `true`, otherwise, Twitter will reject the authentication request.
|
||||
/// </summary>
|
||||
public bool enableState = true;
|
||||
|
||||
/// <summary>
|
||||
/// The additional query arguments that are used to construct the query string of the authentication request.
|
||||
///
|
||||
/// This is useful when you want to add some custom parameters to the authentication request. This string will be
|
||||
/// appended to the query string that constructed from `GetAuthenticationUriArguments`.
|
||||
///
|
||||
/// For example, if you set `prompt=consent&ui_locales=en`, it will be contained in the final authentication query.
|
||||
/// </summary>
|
||||
public string additionalAuthenticationUriQuery = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The token object from Twitter. Check `UniWebViewAuthenticationStandardToken` for more.
|
||||
/// </summary>
|
||||
public class UniWebViewAuthenticationTwitterToken : UniWebViewAuthenticationStandardToken { }
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 86840692470304a76b6d2ac73771b7af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
//
|
||||
// UniWebViewAuthenticationSession.cs
|
||||
// Created by Wang Wei(@onevcat) on 2022-06-21.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using UnityEngine;
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a session that can be used to authenticate a user through a web service.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Initialize the session with a URL that points to the authentication webpage. A browser or a secure web view loads
|
||||
/// and displays the page. On completion, the service sends a callback URL to the session with an authentication token,
|
||||
/// and this triggers the `OnAuthenticationFinished` with the received URL. To make your app be invoked by the system,
|
||||
/// you need to also add the correct callback URL starting with the value of `CallbackScheme` to UniWebView's preferences.
|
||||
///
|
||||
/// Usually this session processes an OAuth 2 flow. It will be used along with a following "exchange token" request, to
|
||||
/// finally get the user's access token to allow you use the service APIs on behalf of the user. This token exchange can
|
||||
/// happen in the client app, or you can pass the code to your server and let your server do the left work.
|
||||
///
|
||||
/// UniWebView also provides built-in integrated authentication flows for several popular service. The the
|
||||
/// `UniWebViewAuthenticationFlow` cluster classes to use them and simplify your work. If the built-in models do not
|
||||
/// fit your work, you can use this class as a starting point of your own authentication integration.
|
||||
///
|
||||
/// See https://docs.uniwebview.com/guide/oauth2.html for a more detailed guide of authentication in UniWebView.
|
||||
/// </remarks>
|
||||
public class UniWebViewAuthenticationSession: UnityEngine.Object {
|
||||
/// <summary>
|
||||
/// Delegate for authentication session finished event.
|
||||
/// </summary>
|
||||
/// <param name="session">The session which raised this event.</param>
|
||||
/// <param name="url">
|
||||
/// The received URL from service. It might contain a valid `code` from the service, or an error.
|
||||
/// </param>
|
||||
public delegate void AuthenticationFinishedDelegate(UniWebViewAuthenticationSession session, string url);
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the session finishes authentication.
|
||||
///
|
||||
/// This event will be invoked when the service provider calls the callback URL. regardless of the authentication code
|
||||
/// is retrieved or an error is returned in the callback URL.
|
||||
/// </summary>
|
||||
public event AuthenticationFinishedDelegate OnAuthenticationFinished;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate for authentication session error encounter event.
|
||||
/// </summary>
|
||||
/// <param name="session">The session which raised this event.</param>
|
||||
/// <param name="errorCode">The error code represents the error type.</param>
|
||||
/// <param name="errorMessage">The error message describes the error in detail.</param>
|
||||
public delegate void AuthErrorReceivedDelegate(UniWebViewAuthenticationSession session, int errorCode, string errorMessage);
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the session encounters an error.
|
||||
///
|
||||
/// This event will be invoked when the authentication session cannot finishes with a URL callback. This usually
|
||||
/// happens when a network error or the user dismisses the authentication page from native UI.
|
||||
/// </summary>
|
||||
public event AuthErrorReceivedDelegate OnAuthenticationErrorReceived;
|
||||
|
||||
private readonly string id = Guid.NewGuid().ToString();
|
||||
private UniWebViewNativeListener listener;
|
||||
|
||||
/// <summary>
|
||||
/// The URL of the authentication webpage. This is the value you used to create this session.
|
||||
/// </summary>
|
||||
public string Url { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The callback scheme of the authentication webpage. This is the value you used to create this session. The service
|
||||
/// is expected to use a URL with this scheme to return to your app.
|
||||
/// </summary>
|
||||
public string CallbackScheme { get; private set; }
|
||||
|
||||
internal void InternalAuthenticationFinished(string url) {
|
||||
if (OnAuthenticationFinished != null) {
|
||||
OnAuthenticationFinished(this, url);
|
||||
}
|
||||
UniWebViewNativeListener.RemoveListener(listener.Name);
|
||||
Destroy(listener.gameObject);
|
||||
}
|
||||
|
||||
internal void InternalAuthenticationErrorReceived(UniWebViewNativeResultPayload payload) {
|
||||
if (OnAuthenticationErrorReceived != null) {
|
||||
int errorCode = int.TryParse(payload.resultCode, out errorCode) ? errorCode : -1;
|
||||
OnAuthenticationErrorReceived(this, errorCode, payload.data);
|
||||
}
|
||||
|
||||
UniWebViewNativeListener.RemoveListener(listener.Name);
|
||||
Destroy(listener.gameObject);
|
||||
}
|
||||
|
||||
private UniWebViewAuthenticationSession() {
|
||||
var listenerObject = new GameObject("UniWebViewAuthSession-" + id);
|
||||
listener = listenerObject.AddComponent<UniWebViewNativeListener>();
|
||||
UniWebViewNativeListener.AddListener(listener);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check whether the current device and system supports the authentication session.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property always returns `true` on iOS 11, macOS 10.15 and later. On Android, it depends on whether there
|
||||
/// is an Intent can handle the safe browsing request, which is use to display the authentication page. Usually
|
||||
/// it is provided by Chrome. If there is no Intent can open the URL in safe browsing mode, this property will
|
||||
/// return `false`.
|
||||
///
|
||||
/// To use this API on Android when you set your Target SDK to Android 11 or later, you need to declare the correct
|
||||
/// intent query explicitly in your AndroidManifest.xml, to follow the Package Visibility
|
||||
/// (https://developer.android.com/about/versions/11/privacy/package-visibility):
|
||||
///
|
||||
/// ```xml
|
||||
/// <queries>
|
||||
/// <intent>
|
||||
/// <action android:name="android.support.customtabs.action.CustomTabsService" />
|
||||
/// </intent>
|
||||
/// </queries>
|
||||
/// ```
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// Returns `true` if the safe browsing mode is supported and the page will be opened in safe browsing
|
||||
/// mode. Otherwise, `false`.
|
||||
/// </returns>
|
||||
public static bool IsAuthenticationSupported => UniWebViewInterface.IsAuthenticationIsSupported();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new authentication session with a given authentication page URL and a callback scheme.
|
||||
/// </summary>
|
||||
/// <param name="url">
|
||||
/// The authentication page which is provided by the service. It should be a URL with some information like your app's
|
||||
/// client id and required scopes, etc.
|
||||
/// </param>
|
||||
/// <param name="callbackScheme">The URL scheme which the service will use to navigate back to your client app.</param>
|
||||
/// <returns></returns>
|
||||
public static UniWebViewAuthenticationSession Create(string url, string callbackScheme) {
|
||||
var session = new UniWebViewAuthenticationSession();
|
||||
session.listener.session = session;
|
||||
session.Url = url;
|
||||
session.CallbackScheme = callbackScheme;
|
||||
|
||||
UniWebViewInterface.AuthenticationInit(session.listener.Name, url, callbackScheme);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the authentication session process. It will show up a secured web page and navigate users to the `Url`.
|
||||
/// </summary>
|
||||
public void Start() {
|
||||
UniWebViewInterface.AuthenticationStart(listener.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels the authentication session.
|
||||
///
|
||||
/// This method is only available on iOS.
|
||||
/// </summary>
|
||||
internal void Cancel() {
|
||||
#if UNITY_IOS && !UNITY_EDITOR
|
||||
UniWebViewInterface.AuthenticationCancel(listener.Name);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets to use the private mode for the authentication. If running under private mode, the previous stored
|
||||
/// authentication information will not be used.
|
||||
/// <remarks>
|
||||
/// On Apple's platform, this works from iOS 13 and macOS 10.15. On Android, this depends on the Chrome setting on the
|
||||
/// device. The users should enable the "incognito" and "third-party incognito" to allow to use this feature.
|
||||
///
|
||||
/// Check them in Chrome app:
|
||||
/// chrome://flags/#cct-incognito
|
||||
/// chrome://flags/#cct-incognito-available-to-third-party
|
||||
/// </remarks>
|
||||
/// </summary>
|
||||
/// <param name="flag">Whether the session should run in private mode or not.</param>
|
||||
public void SetPrivateMode(bool flag) {
|
||||
UniWebViewInterface.AuthenticationSetPrivateMode(listener.Name, flag);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e5e52f46b3fba4e1c868230b0da9fd5f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
//
|
||||
// UniWebViewAuthenticationStandardToken.cs
|
||||
// Created by Wang Wei (@onevcat) on 2022-06-25.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the standard token used in the OAuth 2 process.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class UniWebViewAuthenticationStandardToken {
|
||||
// Unity's JsonUtility.FromJson is quite stupid on this.
|
||||
// Switch to Newtonsoft.Json when we can support from Unity 2021.
|
||||
[SerializeField]
|
||||
private string access_token = default;
|
||||
/// <summary>
|
||||
/// The access token retrieved from the service provider.
|
||||
///
|
||||
/// This usually comes from the `access_token` field in the response.
|
||||
/// Use this token to access the service provider's API.
|
||||
///
|
||||
/// If you do not need the token "offline", just use it and discard. UniWebView will not store this token, if you
|
||||
/// need to keep it for other purpose, please make sure you do not violate any policies and put it to a secure
|
||||
/// place yourself.
|
||||
/// </summary>
|
||||
public string AccessToken => access_token;
|
||||
|
||||
[SerializeField]
|
||||
private string scope = default;
|
||||
/// <summary>
|
||||
/// The granted scopes of the token. This is usually comes from the `scope` field in the response.
|
||||
///
|
||||
/// If there are optional scopes in the initial auth request, the user can choose to not give you some of the
|
||||
/// permissions. Check this field before you use the access token to perform certain actions to avoid failure
|
||||
/// before actual attempts.
|
||||
/// </summary>
|
||||
public string Scope => scope;
|
||||
|
||||
[SerializeField]
|
||||
private string token_type = default;
|
||||
/// <summary>
|
||||
/// The token type. This usually comes from the `token_type` field in the response.
|
||||
///
|
||||
/// For most OAuth 2.0 services, it is fixed to `Bearer`.
|
||||
/// </summary>
|
||||
public string TokenType => token_type;
|
||||
|
||||
[SerializeField]
|
||||
private string refresh_token = default;
|
||||
/// <summary>
|
||||
/// The refresh token retrieved from the service provider. This usually comes from the `refresh_token` field in the
|
||||
/// response.
|
||||
///
|
||||
/// If the access token is refreshable, you can use this
|
||||
/// refresh token to perform a refresh operation and get a new access token without the user's consent again.
|
||||
///
|
||||
/// The refresh policy can be different from the service providers. Read the documentation of the service provider
|
||||
/// to determine the use of refresh token.
|
||||
///
|
||||
/// If the response does not contain a refresh token, this field will be `null`.
|
||||
/// </summary>
|
||||
public string RefreshToken => refresh_token;
|
||||
|
||||
[SerializeField]
|
||||
private long expires_in = default;
|
||||
/// <summary>
|
||||
/// How long does this token remain valid. This usually comes from the `expires_in` field in the response.
|
||||
/// </summary>
|
||||
public long ExpiresIn => expires_in;
|
||||
|
||||
[SerializeField]
|
||||
private string id_token = default;
|
||||
/// <summary>
|
||||
/// The ID token retrieved from the service provider. This usually comes from the `id_token` field in the response.
|
||||
///
|
||||
/// If the service provider does not support ID token or you did not apply for it, this field will be `null`.
|
||||
/// The ID token is usually a JWT token that contains information about the user.
|
||||
/// </summary>
|
||||
public string IdToken => id_token;
|
||||
|
||||
/// <summary>
|
||||
/// The raw value of the response of the exchange token request.
|
||||
///
|
||||
/// If the predefined fields are not enough, you can parse the raw value to get the extra information.
|
||||
/// </summary>
|
||||
public string RawValue { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Util class to generate the standard token from a JSON based exchange token response.
|
||||
/// </summary>
|
||||
/// <typeparam name="TToken">The type of target token.</typeparam>
|
||||
public abstract class UniWebViewAuthenticationTokenFactory<TToken> where TToken : UniWebViewAuthenticationStandardToken {
|
||||
public static TToken Parse(string result) {
|
||||
var json = JsonUtility.FromJson<TToken>(result);
|
||||
json.RawValue = result;
|
||||
if (json.AccessToken == null) {
|
||||
throw AuthenticationResponseException.InvalidResponse(result);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bda3fe59d0bb48c890f1545b0b22dee4
|
||||
timeCreated: 1656308530
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
//
|
||||
// UniWebViewAuthenticationUtils.cs
|
||||
// Created by Wang Wei (@onevcat) on 2022-06-25.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
/// <summary>
|
||||
/// This class provides some helper utils for performing the authentication flow.
|
||||
///
|
||||
/// They are used inside the built-in flows, but you can also use them to implement your own flow.
|
||||
/// </summary>
|
||||
public class UniWebViewAuthenticationUtils {
|
||||
internal static Dictionary<string, string> ParseFormUrlEncodedString(string input) {
|
||||
var result = new Dictionary<string, string>();
|
||||
if (input.StartsWith("?") || input.StartsWith("#")) {
|
||||
input = input.Substring(1);
|
||||
}
|
||||
|
||||
var pairs = input.Split('&');
|
||||
foreach (var pair in pairs) {
|
||||
var kv = pair.Split('=');
|
||||
result.Add(UnityWebRequest.UnEscapeURL(kv[0]), UnityWebRequest.UnEscapeURL(kv[1]));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a random Base64 encoded string.
|
||||
/// </summary>
|
||||
/// <returns>A random Base64 encoded string.</returns>
|
||||
public static string GenerateRandomBase64String() {
|
||||
var randomNumber = new byte[32];
|
||||
string value = "";
|
||||
using (var rng = RandomNumberGenerator.Create()) {
|
||||
rng.GetBytes(randomNumber);
|
||||
value = Convert.ToBase64String(randomNumber);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a random Base64URL encoded string.
|
||||
/// </summary>
|
||||
/// <returns>A random Base64URL encoded string.</returns>
|
||||
public static string GenerateRandomBase64URLString() {
|
||||
var value = GenerateRandomBase64String();
|
||||
return ConvertToBase64URLString(value);
|
||||
}
|
||||
|
||||
static readonly char[] padding = { '=' };
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Base64 encoded string to a Base64URL encoded string.
|
||||
/// </summary>
|
||||
/// <param name="input">The Base64 encoded string.</param>
|
||||
/// <returns>A string with Base64URL encoded for the input.</returns>
|
||||
public static string ConvertToBase64URLString(string input) {
|
||||
return input.TrimEnd(padding).Replace('+', '-').Replace('/', '_');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Base64URL encoded string to a Base64 encoded string.
|
||||
/// </summary>
|
||||
/// <param name="input">The Base64URL encoded string.</param>
|
||||
/// <returns>A string with Base64 encoded for the input.</returns>
|
||||
public static string ConvertToBase64String(string input) {
|
||||
var result = input.Replace('_', '/').Replace('-', '+');
|
||||
switch (input.Length % 4) {
|
||||
case 2:
|
||||
result += "==";
|
||||
break;
|
||||
case 3:
|
||||
result += "=";
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a code verifier for PKCE usage.
|
||||
/// </summary>
|
||||
/// <param name="length">The length of the target code verifier. Default is 64.</param>
|
||||
/// <returns>A generated code verifier for PKCE usage.</returns>
|
||||
public static string GenerateCodeVerifier(int length = 64) {
|
||||
var randomNumber = new byte[32];
|
||||
string value;
|
||||
|
||||
using var rng = RandomNumberGenerator.Create();
|
||||
rng.GetBytes(randomNumber);
|
||||
const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
|
||||
var random = new Random(System.BitConverter.ToInt32(randomNumber, 0));
|
||||
value = new string(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the code challenge for PKCE usage, with a given code verifier and hash method.
|
||||
/// </summary>
|
||||
/// <param name="codeVerifier">The code verifier you generated.</param>
|
||||
/// <param name="method">The hash method you want to use.</param>
|
||||
/// <returns>The result of the code challenge.</returns>
|
||||
public static string CalculateCodeChallenge(string codeVerifier, UniWebViewAuthenticationPKCE method) {
|
||||
switch (method) {
|
||||
case UniWebViewAuthenticationPKCE.None:
|
||||
throw new ArgumentOutOfRangeException(nameof(method), method, null);
|
||||
case UniWebViewAuthenticationPKCE.S256:
|
||||
var sha256 = SHA256.Create();
|
||||
var hash = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(codeVerifier));
|
||||
return ConvertToBase64URLString(System.Convert.ToBase64String(hash));
|
||||
case UniWebViewAuthenticationPKCE.Plain:
|
||||
return codeVerifier;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(method), method, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ConvertPKCEToString(UniWebViewAuthenticationPKCE method) {
|
||||
switch (method) {
|
||||
case UniWebViewAuthenticationPKCE.None:
|
||||
return null;
|
||||
case UniWebViewAuthenticationPKCE.S256:
|
||||
return "S256";
|
||||
case UniWebViewAuthenticationPKCE.Plain:
|
||||
return "plain";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string ConvertIntentUri(string input) {
|
||||
var uri = new Uri(input);
|
||||
if (uri.Scheme != "intent") {
|
||||
return input;
|
||||
}
|
||||
|
||||
var host = uri.Host;
|
||||
string scheme = null;
|
||||
var fragments = uri.Fragment;
|
||||
fragments.Split(';').ToList().ForEach(fragment => {
|
||||
var kv = fragment.Split('=');
|
||||
if (kv.Length == 2 && kv[0] == "scheme") {
|
||||
scheme = kv[1];
|
||||
}
|
||||
});
|
||||
|
||||
if (!String.IsNullOrEmpty(scheme)) {
|
||||
return scheme + "://" + host;
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
public static string CreateQueryString(Dictionary<string, string> collection, string additionalQuery = "") {
|
||||
int count = collection.Count;
|
||||
if (count == 0) {
|
||||
return additionalQuery ?? "";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
string [] keys = collection.Keys.ToArray();
|
||||
for (int i = 0; i < count; i++) {
|
||||
sb.AppendFormat ("{0}={1}&", keys[i], UnityWebRequest.EscapeURL(collection[keys[i]]));
|
||||
}
|
||||
|
||||
if (sb.Length > 0) {
|
||||
if (string.IsNullOrEmpty(additionalQuery)) {
|
||||
sb.Length--;
|
||||
} else {
|
||||
sb.AppendFormat("{0}", additionalQuery);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public enum UniWebViewAuthenticationPKCE
|
||||
{
|
||||
None,
|
||||
S256,
|
||||
Plain
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cb86a1823d1e54d558d6f77e3c36719b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// UniWebViewCacheMode.cs
|
||||
// Created by Wang Wei(@onevcat) on 2024-01-17.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
|
||||
/// <summary>
|
||||
/// Defines the cache mode for UniWebView.
|
||||
/// </summary>
|
||||
public enum UniWebViewCacheMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Default mode. The web view will check the validity of the cache copy when there is one. If the copy is invalid,
|
||||
/// the web view will load from the network. This is the default setting.
|
||||
/// </summary>
|
||||
Default = 0,
|
||||
|
||||
/// <summary>
|
||||
/// No cache is used. All pages are loaded directly from the network. This is useful for applications that do not
|
||||
/// want to have a cache.
|
||||
/// </summary>
|
||||
NoCache = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Prioritize the cache. If there is a copy of the page in the cache, the web view will use it even if the copy
|
||||
/// has expired. The web view will only load from the network when the page does not exist in the cache.
|
||||
/// </summary>
|
||||
CacheElseLoad = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Only use the cache. In this mode, the web view will not load pages from the network, only use the content in
|
||||
/// the cache. If the requested URL is not in the cache, an error is returned.
|
||||
/// </summary>
|
||||
CacheOnly = 3,
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: af9091341ad1451a88060e20c2dc953f
|
||||
timeCreated: 1705494877
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 983375010eb44a88b27df35ee1eedc4f
|
||||
timeCreated: 1682064507
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// UniWebViewChannelMethodHandleRequest.cs
|
||||
// Created by Wang Wei(@onevcat) on 2023-04-21.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the request of a loading used in request handler.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class UniWebViewChannelMethodHandleRequest {
|
||||
[SerializeField]
|
||||
private string url;
|
||||
|
||||
/// <summary>
|
||||
/// The URL of the request.
|
||||
/// </summary>
|
||||
public string Url => url;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e1fb4e291b944fa8b8a114f076f06da9
|
||||
timeCreated: 1682064771
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
//
|
||||
// UniWebViewChannelMethodManager.cs
|
||||
// Created by Wang Wei(@onevcat) on 2023-04-21.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
enum UniWebViewChannelMethod {
|
||||
ShouldUniWebViewHandleRequest,
|
||||
RequestMediaCapturePermission
|
||||
}
|
||||
|
||||
class UniWebViewChannelMethodManager {
|
||||
|
||||
private static UniWebViewChannelMethodManager instance;
|
||||
private Dictionary<string, Dictionary<string, Func<object, object>>> channels =
|
||||
new Dictionary<string, Dictionary<string, Func<object, object>>>();
|
||||
|
||||
internal static UniWebViewChannelMethodManager Instance {
|
||||
get {
|
||||
if (instance == null) {
|
||||
instance = new UniWebViewChannelMethodManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
internal void RegisterChannelMethod(
|
||||
string webViewName,
|
||||
UniWebViewChannelMethod method,
|
||||
Func<object, object> handler)
|
||||
{
|
||||
if (!HasRegisteredChannel(webViewName)) {
|
||||
channels[webViewName] = new Dictionary<string, Func<object, object>>();
|
||||
}
|
||||
var methodName = method.ToString();
|
||||
channels[webViewName][methodName] = handler;
|
||||
UniWebViewLogger.Instance.Info("Channel method is registered for web view: " + webViewName + ", method: " +
|
||||
methodName);
|
||||
}
|
||||
|
||||
internal void UnregisterChannel(string webViewName) {
|
||||
if (!HasRegisteredChannel(webViewName)) {
|
||||
return;
|
||||
}
|
||||
channels.Remove(webViewName);
|
||||
UniWebViewLogger.Instance.Debug("All channel methods are unregistered for web view: " + webViewName);
|
||||
}
|
||||
|
||||
internal void UnregisterChannelMethod(string webViewName, UniWebViewChannelMethod method) {
|
||||
var methodName = method.ToString();
|
||||
if (!HasRegisteredChannel(webViewName)) {
|
||||
return;
|
||||
}
|
||||
channels[webViewName].Remove(methodName);
|
||||
UniWebViewLogger.Instance.Debug("Channel method is unregistered for web view: " + webViewName + ", method: " +
|
||||
methodName);
|
||||
}
|
||||
|
||||
bool HasRegisteredChannel(string webViewName) {
|
||||
return channels.Keys.Contains(webViewName);
|
||||
}
|
||||
|
||||
bool HasRegisteredMethod(string webViewName, string methodName) {
|
||||
if (!HasRegisteredChannel(webViewName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return channels[webViewName].Keys.Contains(methodName);
|
||||
}
|
||||
|
||||
internal string InvokeMethod(string webViewName, string methodName, string parameters) {
|
||||
if (!HasRegisteredMethod(webViewName, methodName)) {
|
||||
UniWebViewLogger.Instance.Info("There is no handler for the channel method. Ignoring.");
|
||||
return null;
|
||||
}
|
||||
var func = channels[webViewName][methodName];
|
||||
|
||||
if (!Enum.TryParse<UniWebViewChannelMethod>(methodName, out var method)) {
|
||||
UniWebViewLogger.Instance.Info("Unknown method name: " + methodName + ". Please check, ignoring.");
|
||||
return null;
|
||||
}
|
||||
|
||||
UniWebViewLogger.Instance.Verbose("Channel method invoking received for web view: " + webViewName + ", method: " +
|
||||
methodName + ", parameters: " + parameters);
|
||||
string result;
|
||||
switch (method) {
|
||||
case UniWebViewChannelMethod.ShouldUniWebViewHandleRequest: {
|
||||
// (UniWebViewChannelMethodHandleRequest) -> bool
|
||||
var input = JsonUtility.FromJson<UniWebViewChannelMethodHandleRequest>(parameters);
|
||||
bool Func(UniWebViewChannelMethodHandleRequest i) => (bool)func(i);
|
||||
result = ResultJsonWith(Func(input));
|
||||
break;
|
||||
}
|
||||
case UniWebViewChannelMethod.RequestMediaCapturePermission: {
|
||||
// (UniWebViewChannelMethodMediaCapturePermission) -> UniWebViewMediaCapturePermissionDecision
|
||||
var input = JsonUtility.FromJson<UniWebViewChannelMethodMediaCapturePermission>(parameters);
|
||||
UniWebViewMediaCapturePermissionDecision Func(UniWebViewChannelMethodMediaCapturePermission i) => (UniWebViewMediaCapturePermissionDecision)func(i);
|
||||
result = ResultJsonWith(Func(input));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
result = null;
|
||||
break;
|
||||
}
|
||||
UniWebViewLogger.Instance.Debug("Channel method handler responded. Result: " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
string ResultJsonWith(bool value) {
|
||||
return value ? "{\"result\":true}" : "{\"result\":false}";
|
||||
}
|
||||
|
||||
string ResultJsonWith(UniWebViewMediaCapturePermissionDecision decision) {
|
||||
switch (decision) {
|
||||
case UniWebViewMediaCapturePermissionDecision.Prompt:
|
||||
return "{\"result\":\"prompt\"}";
|
||||
case UniWebViewMediaCapturePermissionDecision.Grant:
|
||||
return "{\"result\":\"grant\"}";
|
||||
case UniWebViewMediaCapturePermissionDecision.Deny:
|
||||
return "{\"result\":\"deny\"}";
|
||||
default:
|
||||
UniWebViewLogger.Instance.Critical("Unknown decision: " + decision);
|
||||
break;
|
||||
}
|
||||
Debug.LogAssertion("Unrecognized UniWebViewMediaCapturePermissionDecision. Fallback to prompt.");
|
||||
return "{\"result\":\"prompt\"}";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f9415d08641d44ec97fdccd2799861e1
|
||||
timeCreated: 1682063884
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// UniWebViewChannelMethodMediaCapturePermission.cs
|
||||
// Created by Wang Wei(@onevcat) on 2024-02-20.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the request of media capture permission.
|
||||
///
|
||||
/// This class represents the request of media capture permission. When the web page requests the permission to access
|
||||
/// the device's hardware, such as the camera or microphone, UniWebView will ask you to handle the request with a value
|
||||
/// of this class. You can use the values in this class to determine the decision for the permission request.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class UniWebViewChannelMethodMediaCapturePermission {
|
||||
|
||||
[SerializeField]
|
||||
private string protocol;
|
||||
|
||||
[SerializeField]
|
||||
private string host;
|
||||
|
||||
[SerializeField]
|
||||
private int port;
|
||||
|
||||
[SerializeField]
|
||||
private string[] resources;
|
||||
|
||||
/// <summary>
|
||||
/// The protocol used by the permission request. Such as "https" or "http".
|
||||
/// </summary>
|
||||
public string Protocol => protocol;
|
||||
|
||||
/// <summary>
|
||||
/// The host of the origin of the permission request.
|
||||
///
|
||||
/// It is usually the domain of the web page.
|
||||
/// </summary>
|
||||
public string Host => host;
|
||||
|
||||
/// <summary>
|
||||
/// The port of the origin of the permission request.
|
||||
///
|
||||
/// If not existing in the request URL, it is -1.
|
||||
/// </summary>
|
||||
public int Port => port;
|
||||
|
||||
/// <summary>
|
||||
/// The string representation of the resources of the origin of the permission request.
|
||||
///
|
||||
/// An array contains requested resources, the most common values are "VIDEO", "AUDIO". On Android, some pages can
|
||||
/// also requests for "PROTECTED_MEDIA_ID", "MIDI_SYSEX", etc.
|
||||
/// </summary>
|
||||
public string[] Resources => resources;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 31347bc762ad46fda0634683da0201ac
|
||||
timeCreated: 1708439899
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// UniWebViewMediaCapturePermissionDecision.cs
|
||||
// Created by Wang Wei(@onevcat) on 2024-02-20.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
/// <summary>
|
||||
/// Represents the decision of media capture permission request.
|
||||
///
|
||||
/// Use value in this enum to guide how UniWebView should handle the media capture permission request.
|
||||
/// </summary>
|
||||
public enum UniWebViewMediaCapturePermissionDecision {
|
||||
/// <summary>
|
||||
/// Display a prompt to ask user for the permission.
|
||||
///
|
||||
/// The prompt alert shows the origin of the request and the resources requested. It asks user to grant or deny the
|
||||
/// permission.
|
||||
/// </summary>
|
||||
Prompt,
|
||||
|
||||
/// <summary>
|
||||
/// Grant the permission request without asking user.
|
||||
/// </summary>
|
||||
Grant,
|
||||
|
||||
/// <summary>
|
||||
/// Deny the permission request. The web page will receive an error and it knows the request resources are not
|
||||
/// allowed to use.
|
||||
/// </summary>
|
||||
Deny
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 325ac2081331446986f826bce9a5d62e
|
||||
timeCreated: 1708440272
|
||||
42
ProjectNLD/Assets/ThirdParty/UniWebView/Script/UniWebViewContentInsetAdjustmentBehavior.cs
vendored
Normal file
42
ProjectNLD/Assets/ThirdParty/UniWebView/Script/UniWebViewContentInsetAdjustmentBehavior.cs
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// UniWebViewContentInsetAdjustmentBehavior.cs
|
||||
// Created by Wang Wei(@onevcat) on 2019-09-20.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
|
||||
/// <summary>
|
||||
/// Constants indicating how safe area insets are added to the adjusted content inset.
|
||||
/// This is only for iOS.
|
||||
/// </summary>
|
||||
public enum UniWebViewContentInsetAdjustmentBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// Automatically adjust the scroll view insets.
|
||||
/// </summary>
|
||||
Automatic = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Adjust the insets only in the scrollable directions.
|
||||
/// </summary>
|
||||
ScrollableAxes = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Do not adjust the scroll view insets.
|
||||
/// </summary>
|
||||
Never = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Always include the safe area insets in the content adjustment.
|
||||
/// </summary>
|
||||
Always = 3
|
||||
}
|
||||
11
ProjectNLD/Assets/ThirdParty/UniWebView/Script/UniWebViewContentInsetAdjustmentBehavior.cs.meta
vendored
Normal file
11
ProjectNLD/Assets/ThirdParty/UniWebView/Script/UniWebViewContentInsetAdjustmentBehavior.cs.meta
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dc6b999829de442f2aa381a8ff78a917
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
32
ProjectNLD/Assets/ThirdParty/UniWebView/Script/UniWebViewDownloadMatchingType.cs
vendored
Normal file
32
ProjectNLD/Assets/ThirdParty/UniWebView/Script/UniWebViewDownloadMatchingType.cs
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// UniWebViewDownloadMatchingType.cs
|
||||
// Created by Wang Wei(@onevcat) on 2021-09-02.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
|
||||
/// <summary>
|
||||
/// The matching type used when UniWebView determines whether to download from a URL or MIME type.
|
||||
/// </summary>
|
||||
public enum UniWebViewDownloadMatchingType
|
||||
{
|
||||
/// <summary>
|
||||
/// Matches exact the whole value.
|
||||
/// </summary>
|
||||
ExactValue = 1,
|
||||
/// <summary>
|
||||
/// Uses the value as a regular expression.
|
||||
/// </summary>
|
||||
RegularExpression = 2
|
||||
}
|
||||
|
||||
11
ProjectNLD/Assets/ThirdParty/UniWebView/Script/UniWebViewDownloadMatchingType.cs.meta
vendored
Normal file
11
ProjectNLD/Assets/ThirdParty/UniWebView/Script/UniWebViewDownloadMatchingType.cs.meta
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0ba73f1cc351846878c5731b4e22b132
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
121
ProjectNLD/Assets/ThirdParty/UniWebView/Script/UniWebViewEmbeddedToolbar.cs
vendored
Normal file
121
ProjectNLD/Assets/ThirdParty/UniWebView/Script/UniWebViewEmbeddedToolbar.cs
vendored
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the embedded toolbar in a web view.
|
||||
///
|
||||
/// You do not create an instance of this class directly. Instead, use the `EmbeddedWebView` property in `UniWebView` to
|
||||
/// get the current embedded toolbar in the web view and interact with it.
|
||||
///
|
||||
/// The embedded toolbar of a web view expands its width to match the web view's frame width. It is displayed at either
|
||||
/// top or bottom of the web view, based on the setting received through `SetPosition`. By default, the toolbar contains
|
||||
/// a main title, a back button, a forward button and a done button to close the web view. You can use methods in this
|
||||
/// class to customize the toolbar to match your app's style.
|
||||
/// </summary>
|
||||
public class UniWebViewEmbeddedToolbar {
|
||||
|
||||
private readonly UniWebViewNativeListener listener;
|
||||
|
||||
internal UniWebViewEmbeddedToolbar(UniWebViewNativeListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the position of the embedded toolbar. You can put the toolbar at either top or bottom of your web view.
|
||||
/// The default position is `Top`.
|
||||
/// </summary>
|
||||
/// <param name="position">The desired position of the toolbar.</param>
|
||||
public void SetPosition(UniWebViewToolbarPosition position) {
|
||||
UniWebViewInterface.SetEmbeddedToolbarOnTop(listener.Name, position == UniWebViewToolbarPosition.Top);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the toolbar.
|
||||
/// </summary>
|
||||
public void Show() {
|
||||
UniWebViewInterface.SetShowEmbeddedToolbar(listener.Name, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hides the toolbar.
|
||||
/// </summary>
|
||||
public void Hide() {
|
||||
UniWebViewInterface.SetShowEmbeddedToolbar(listener.Name, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the text of the done button. The default text is "Done".
|
||||
/// </summary>
|
||||
/// <param name="text">The desired text to display as the done button.</param>
|
||||
public void SetDoneButtonText(string text) {
|
||||
UniWebViewInterface.SetEmbeddedToolbarDoneButtonText(listener.Name, text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the text of the back button. The default text is "❮" ("\u276E").
|
||||
/// </summary>
|
||||
/// <param name="text">The desired text to display as the back button.</param>
|
||||
public void SetGoBackButtonText(string text) {
|
||||
UniWebViewInterface.SetEmbeddedToolbarGoBackButtonText(listener.Name, text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the text of the forward button. The default text is "❯" ("\u276F").
|
||||
/// </summary>
|
||||
/// <param name="text">The desired text to display as the forward button.</param>
|
||||
public void SetGoForwardButtonText(string text) {
|
||||
UniWebViewInterface.SetEmbeddedToolbarGoForwardButtonText(listener.Name, text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the text of toolbar title. The default is empty. The space is limited, setting a long text as title might
|
||||
/// not fit in the space.
|
||||
/// </summary>
|
||||
/// <param name="text">The desired text to display as the title in the toolbar.</param>
|
||||
public void SetTitleText(string text) {
|
||||
UniWebViewInterface.SetEmbeddedToolbarTitleText(listener.Name, text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the background color of the toolbar.
|
||||
/// </summary>
|
||||
/// <param name="color">The desired color of toolbar's background.</param>
|
||||
public void SetBackgroundColor(Color color) {
|
||||
UniWebViewInterface.SetEmbeddedToolbarBackgroundColor(listener.Name, color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the buttons color of the toolbar. This color affects the back, forward and done button.
|
||||
/// </summary>
|
||||
/// <param name="color">The desired color of toolbar's buttons.</param>
|
||||
public void SetButtonTextColor(Color color) {
|
||||
UniWebViewInterface.SetEmbeddedToolbarButtonTextColor(listener.Name, color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the text color of the toolbar title.
|
||||
/// </summary>
|
||||
/// <param name="color">The desired color of the toolbar's title.</param>
|
||||
public void SetTitleTextColor(Color color) {
|
||||
UniWebViewInterface.SetEmbeddedToolbarTitleTextColor(listener.Name, color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hides the navigation buttons on the toolbar.
|
||||
///
|
||||
/// When called, the back button and forward button will not be shown.
|
||||
/// By default, the navigation buttons are shown.
|
||||
/// </summary>
|
||||
public void HideNavigationButtons() {
|
||||
UniWebViewInterface.SetEmeddedToolbarNavigationButtonsShow(listener.Name, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the navigation buttons on the toolbar.
|
||||
///
|
||||
/// When called, the back button and forward button will be shown.
|
||||
/// By default, the navigation buttons are shown.
|
||||
/// </summary>
|
||||
public void ShowNavigationButtons() {
|
||||
UniWebViewInterface.SetEmeddedToolbarNavigationButtonsShow(listener.Name, true);
|
||||
}
|
||||
}
|
||||
3
ProjectNLD/Assets/ThirdParty/UniWebView/Script/UniWebViewEmbeddedToolbar.cs.meta
vendored
Normal file
3
ProjectNLD/Assets/ThirdParty/UniWebView/Script/UniWebViewEmbeddedToolbar.cs.meta
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 19945236afb94be88f39e5f6c566ce71
|
||||
timeCreated: 1658065034
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
// UniWebViewHelper.cs
|
||||
// Created by Wang Wei(@onevcat) on 2017-04-11.
|
||||
//
|
||||
// This file is a part of UniWebView Project (https://uniwebview.com)
|
||||
// By purchasing the asset, you are allowed to use this code in as many as projects
|
||||
// you want, only if you publish the final products under the name of the same account
|
||||
// used for the purchase.
|
||||
//
|
||||
// This asset and all corresponding files (such as source code) are provided on an
|
||||
// “as is” basis, without warranty of any kind, express of implied, including but not
|
||||
// limited to the warranties of merchantability, fitness for a particular purpose, and
|
||||
// noninfringement. In no event shall the authors or copyright holders be liable for any
|
||||
// claim, damages or other liability, whether in action of contract, tort or otherwise,
|
||||
// arising from, out of or in connection with the software or the use of other dealing in the software.
|
||||
//
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
|
||||
/// <summary>
|
||||
/// Provides some helper utility methods for UniWebView.
|
||||
/// </summary>
|
||||
public class UniWebViewHelper {
|
||||
/// <summary>
|
||||
/// Get the local streaming asset path for a given file path related to the StreamingAssets folder.
|
||||
///
|
||||
/// This method will help you to create a URL string for a file under your StreamingAssets folder for different platforms.
|
||||
/// <param name="path">The relative path to the Assets/StreamingAssets of your file.
|
||||
/// For example, if you placed a html file under Assets/StreamingAssets/www/index.html, you should pass `www/index.html` as parameter.
|
||||
/// </param>
|
||||
/// <returns>The path you could use as the url for the web view.</returns>
|
||||
public static string StreamingAssetURLForPath(string path)
|
||||
{
|
||||
#if (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX || UNITY_IOS) && !UNITY_EDITOR_WIN && !UNITY_EDITOR_LINUX
|
||||
return Path.Combine("file://" + Application.streamingAssetsPath, path);
|
||||
#elif UNITY_ANDROID && !UNITY_EDITOR_WIN && !UNITY_EDITOR_LINUX
|
||||
return Path.Combine("file:///android_asset/", path);
|
||||
#else
|
||||
UniWebViewLogger.Instance.Critical("The current build target is not supported.");
|
||||
return string.Empty;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the local persistent data path for a given file path related to the data folder of your host app.
|
||||
///
|
||||
/// This method will help you to create a URL string for a file under you stored in the `persistentDataPath`.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// The relative path to the persistent data path of your file.
|
||||
/// </param>
|
||||
/// <returns>The path you could use as the url for the web view.</returns>
|
||||
public static string PersistentDataURLForPath(string path)
|
||||
{
|
||||
return Path.Combine("file://" + Application.persistentDataPath, path);
|
||||
}
|
||||
|
||||
internal static bool IsEditor {
|
||||
get {
|
||||
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue