LuanShi hace 3 meses
commit
ade3874a2c
Se han modificado 160 ficheros con 15847 adiciones y 0 borrados
  1. BIN
      Assets/16game.png
  2. +132
    -0
      Assets/16game.png.meta
  3. +8
    -0
      Assets/Editor.meta
  4. +8
    -0
      Assets/Editor/UniWebView.meta
  5. +26
    -0
      Assets/Editor/UniWebView/settings.asset
  6. +8
    -0
      Assets/Editor/UniWebView/settings.asset.meta
  7. +21
    -0
      Assets/Init.cs
  8. +11
    -0
      Assets/Init.cs.meta
  9. +9
    -0
      Assets/Plugins.meta
  10. +8
    -0
      Assets/Plugins/Android.meta
  11. +17
    -0
      Assets/Plugins/Android/AndroidManifest.xml
  12. +7
    -0
      Assets/Plugins/Android/AndroidManifest.xml.meta
  13. BIN
      Assets/Plugins/Android/UniWebView.aar
  14. +32
    -0
      Assets/Plugins/Android/UniWebView.aar.meta
  15. +34
    -0
      Assets/Plugins/UniWebView.bundle.meta
  16. +8
    -0
      Assets/Plugins/UniWebView.bundle/Contents.meta
  17. +48
    -0
      Assets/Plugins/UniWebView.bundle/Contents/Info.plist
  18. +7
    -0
      Assets/Plugins/UniWebView.bundle/Contents/Info.plist.meta
  19. +8
    -0
      Assets/Plugins/UniWebView.bundle/Contents/MacOS.meta
  20. BIN
      Assets/Plugins/UniWebView.bundle/Contents/MacOS/UniWebView
  21. +7
    -0
      Assets/Plugins/UniWebView.bundle/Contents/MacOS/UniWebView.meta
  22. +8
    -0
      Assets/Plugins/UniWebView.bundle/Contents/_CodeSignature.meta
  23. +115
    -0
      Assets/Plugins/UniWebView.bundle/Contents/_CodeSignature/CodeResources
  24. +7
    -0
      Assets/Plugins/UniWebView.bundle/Contents/_CodeSignature/CodeResources.meta
  25. +8
    -0
      Assets/Plugins/iOS.meta
  26. BIN
      Assets/Plugins/iOS/libUniWebView.a
  27. +33
    -0
      Assets/Plugins/iOS/libUniWebView.a.meta
  28. +8
    -0
      Assets/Scenes.meta
  29. +267
    -0
      Assets/Scenes/SampleScene.unity
  30. +7
    -0
      Assets/Scenes/SampleScene.unity.meta
  31. +373
    -0
      Assets/Scenes/Start.unity
  32. +7
    -0
      Assets/Scenes/Start.unity.meta
  33. +9
    -0
      Assets/UniWebView.meta
  34. +1697
    -0
      Assets/UniWebView/CHANGELOG.md
  35. +8
    -0
      Assets/UniWebView/CHANGELOG.md.meta
  36. +9
    -0
      Assets/UniWebView/Demo.meta
  37. +318
    -0
      Assets/UniWebView/Demo/UniWebViewDemo.unity
  38. +8
    -0
      Assets/UniWebView/Demo/UniWebViewDemo.unity.meta
  39. +8
    -0
      Assets/UniWebView/Editor.meta
  40. +237
    -0
      Assets/UniWebView/Editor/AndroidManifest.cs
  41. +11
    -0
      Assets/UniWebView/Editor/AndroidManifest.cs.meta
  42. +346
    -0
      Assets/UniWebView/Editor/BuildGradle.cs
  43. +11
    -0
      Assets/UniWebView/Editor/BuildGradle.cs.meta
  44. +47
    -0
      Assets/UniWebView/Editor/GradleProperty.cs
  45. +11
    -0
      Assets/UniWebView/Editor/GradleProperty.cs.meta
  46. +15
    -0
      Assets/UniWebView/Editor/UniWebView-CSharp.Editor.asmdef
  47. +7
    -0
      Assets/UniWebView/Editor/UniWebView-CSharp.Editor.asmdef.meta
  48. +219
    -0
      Assets/UniWebView/Editor/UniWebViewEditorSettings.cs
  49. +11
    -0
      Assets/UniWebView/Editor/UniWebViewEditorSettings.cs.meta
  50. +337
    -0
      Assets/UniWebView/Editor/UniWebViewPostBuildProcessor.cs
  51. +11
    -0
      Assets/UniWebView/Editor/UniWebViewPostBuildProcessor.cs.meta
  52. +9
    -0
      Assets/UniWebView/Interface.meta
  53. +568
    -0
      Assets/UniWebView/Interface/UniWebViewAndroid.cs
  54. +12
    -0
      Assets/UniWebView/Interface/UniWebViewAndroid.cs.meta
  55. +40
    -0
      Assets/UniWebView/Interface/UniWebViewAndroidStaticListener.cs
  56. +13
    -0
      Assets/UniWebView/Interface/UniWebViewAndroidStaticListener.cs.meta
  57. +898
    -0
      Assets/UniWebView/Interface/UniWebViewCocoa.cs
  58. +12
    -0
      Assets/UniWebView/Interface/UniWebViewCocoa.cs.meta
  59. +113
    -0
      Assets/UniWebView/Interface/UniWebViewPlaceholder.cs
  60. +12
    -0
      Assets/UniWebView/Interface/UniWebViewPlaceholder.cs.meta
  61. +9
    -0
      Assets/UniWebView/Prefab.meta
  62. +60
    -0
      Assets/UniWebView/Prefab/UniWebView.prefab
  63. +9
    -0
      Assets/UniWebView/Prefab/UniWebView.prefab.meta
  64. +46
    -0
      Assets/UniWebView/Prefab/UniWebViewSafeBrowsing.prefab
  65. +7
    -0
      Assets/UniWebView/Prefab/UniWebViewSafeBrowsing.prefab.meta
  66. +30
    -0
      Assets/UniWebView/README.txt
  67. +8
    -0
      Assets/UniWebView/README.txt.meta
  68. +9
    -0
      Assets/UniWebView/Script.meta
  69. +8
    -0
      Assets/UniWebView/Script/External.meta
  70. +551
    -0
      Assets/UniWebView/Script/External/MiniJSON.cs
  71. +11
    -0
      Assets/UniWebView/Script/External/MiniJSON.cs.meta
  72. +2242
    -0
      Assets/UniWebView/Script/UniWebView.cs
  73. +12
    -0
      Assets/UniWebView/Script/UniWebView.cs.meta
  74. +8
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication.meta
  75. +94
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationCommonFlow.cs
  76. +11
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationCommonFlow.cs.meta
  77. +356
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlow.cs
  78. +11
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlow.cs.meta
  79. +230
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowCustomize.cs
  80. +11
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowCustomize.cs.meta
  81. +222
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowDiscord.cs
  82. +11
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowDiscord.cs.meta
  83. +217
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowFacebook.cs
  84. +11
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowFacebook.cs.meta
  85. +255
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowGitHub.cs
  86. +11
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowGitHub.cs.meta
  87. +231
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowGoogle.cs
  88. +3
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowGoogle.cs.meta
  89. +227
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowLine.cs
  90. +11
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowLine.cs.meta
  91. +211
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowTwitter.cs
  92. +11
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowTwitter.cs.meta
  93. +182
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationSession.cs
  94. +11
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationSession.cs.meta
  95. +116
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationStandardToken.cs
  96. +3
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationStandardToken.cs.meta
  97. +198
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationUtils.cs
  98. +11
    -0
      Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationUtils.cs.meta
  99. +45
    -0
      Assets/UniWebView/Script/UniWebViewCacheMode.cs
  100. +3
    -0
      Assets/UniWebView/Script/UniWebViewCacheMode.cs.meta

BIN
Assets/16game.png Ver fichero

Antes Después
Anchura: 256  |  Altura: 256  |  Tamaño: 26 KiB

+ 132
- 0
Assets/16game.png.meta Ver fichero

@@ -0,0 +1,132 @@
fileFormatVersion: 2
guid: b7972444e74a3874296bed0afbef3b37
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

+ 8
- 0
Assets/Editor.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 28c55975e69947e48a9407bb833a7ac9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 8
- 0
Assets/Editor/UniWebView.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a81820dc80e59154c961c01c6d42781e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 26
- 0
Assets/Editor/UniWebView/settings.asset Ver fichero

@@ -0,0 +1,26 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a403a09e241a0480a957591ea60fb785, type: 3}
m_Name: settings
m_EditorClassIdentifier:
usesCleartextTraffic: 0
writeExternalStorage: 0
accessFineLocation: 0
addsKotlin: 1
kotlinVersion:
addsAndroidBrowser: 1
androidBrowserVersion:
addsAndroidXCore: 0
androidXCoreVersion:
enableJetifier: 1
authCallbackUrls: []
supportLINELogin: 0

+ 8
- 0
Assets/Editor/UniWebView/settings.asset.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f4e3e511116a133428f348c027b47bfa
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

+ 21
- 0
Assets/Init.cs Ver fichero

@@ -0,0 +1,21 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Init : MonoBehaviour
{
[SerializeField]
private UniWebView m_UniWebView;
// Start is called before the first frame update
void Start()
{
m_UniWebView.SetBackButtonEnabled(false);// 回退钮 物理按键
}
// Update is called once per frame
void Update()
{
}
}

+ 11
- 0
Assets/Init.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4f155601221f7e24ab1909afd0e4121a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 9
- 0
Assets/Plugins.meta Ver fichero

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: d3dad2b92748d439e851e10d4f4ecaf0
folderAsset: yes
timeCreated: 1489325633
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

+ 8
- 0
Assets/Plugins/Android.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3916a9bfa4fd449e2827f2f20897a7d7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 17
- 0
Assets/Plugins/Android/AndroidManifest.xml Ver fichero

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unity3d.player"
xmlns:tools="http://schemas.android.com/tools">
<application android:usesCleartextTraffic="true">
<activity android:name="com.unity3d.player.UnityPlayerActivity"
android:theme="@style/UnityThemeSelector">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
</application>
</manifest>

+ 7
- 0
Assets/Plugins/Android/AndroidManifest.xml.meta Ver fichero

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 669f8dedf59caa842abee26fe99bfcd5
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Plugins/Android/UniWebView.aar Ver fichero


+ 32
- 0
Assets/Plugins/Android/UniWebView.aar.meta Ver fichero

@@ -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:

+ 34
- 0
Assets/Plugins/UniWebView.bundle.meta Ver fichero

@@ -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
- 0
Assets/Plugins/UniWebView.bundle/Contents.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 19150ffd969374afd9b181cd8c71f662
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 48
- 0
Assets/Plugins/UniWebView.bundle/Contents/Info.plist Ver fichero

@@ -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>23F79</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></string>
<key>DTPlatformName</key>
<string>macosx</string>
<key>DTPlatformVersion</key>
<string>14.5</string>
<key>DTSDKBuild</key>
<string>23F73</string>
<key>DTSDKName</key>
<string>macosx14.5</string>
<key>DTXcode</key>
<string>1540</string>
<key>DTXcodeBuild</key>
<string>15F31d</string>
<key>LSMinimumSystemVersion</key>
<string>10.11</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2017年 OneV's Den. All rights reserved.</string>
</dict>
</plist>

+ 7
- 0
Assets/Plugins/UniWebView.bundle/Contents/Info.plist.meta Ver fichero

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6ed4d1ad77ba246f0aa50cb883ca2973
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 8
- 0
Assets/Plugins/UniWebView.bundle/Contents/MacOS.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 495312126946747a3b197461eaff9687
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Plugins/UniWebView.bundle/Contents/MacOS/UniWebView Ver fichero


+ 7
- 0
Assets/Plugins/UniWebView.bundle/Contents/MacOS/UniWebView.meta Ver fichero

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0168f4971f50d488e959c40d05b94c59
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 8
- 0
Assets/Plugins/UniWebView.bundle/Contents/_CodeSignature.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 80fcb824c01d44613803213f4b1ed096
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 115
- 0
Assets/Plugins/UniWebView.bundle/Contents/_CodeSignature/CodeResources Ver fichero

@@ -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>

+ 7
- 0
Assets/Plugins/UniWebView.bundle/Contents/_CodeSignature/CodeResources.meta Ver fichero

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f0a1c562a4f234a5c80db8830befc067
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 8
- 0
Assets/Plugins/iOS.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 10cf9bec133da4d3b836f29204deca1b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Plugins/iOS/libUniWebView.a Ver fichero


+ 33
- 0
Assets/Plugins/iOS/libUniWebView.a.meta Ver fichero

@@ -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:

+ 8
- 0
Assets/Scenes.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5d77f90ac1519fd43918145191e2c5eb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 267
- 0
Assets/Scenes/SampleScene.unity Ver fichero

@@ -0,0 +1,267 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 705507994}
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
m_GIWorkflowMode: 1
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 500
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 500
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 2
m_PVRDenoiserTypeDirect: 0
m_PVRDenoiserTypeIndirect: 0
m_PVRDenoiserTypeAO: 0
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 0
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_LightingSettings: {fileID: 0}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 2
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &705507993
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 705507995}
- component: {fileID: 705507994}
m_Layer: 0
m_Name: Directional Light
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!108 &705507994
Light:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 705507993}
m_Enabled: 1
serializedVersion: 8
m_Type: 1
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
m_Intensity: 1
m_Range: 10
m_SpotAngle: 30
m_CookieSize: 10
m_Shadows:
m_Type: 2
m_Resolution: -1
m_CustomResolution: -1
m_Strength: 1
m_Bias: 0.05
m_NormalBias: 0.4
m_NearPlane: 0.2
m_Cookie: {fileID: 0}
m_DrawHalo: 0
m_Flare: {fileID: 0}
m_RenderMode: 0
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_Lightmapping: 1
m_LightShadowCasterMode: 0
m_AreaSize: {x: 1, y: 1}
m_BounceIntensity: 1
m_ColorTemperature: 6570
m_UseColorTemperature: 0
m_ShadowRadius: 0
m_ShadowAngle: 0
--- !u!4 &705507995
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 705507993}
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
m_LocalPosition: {x: 0, y: 3, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
--- !u!1 &963194225
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 963194228}
- component: {fileID: 963194227}
- component: {fileID: 963194226}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!81 &963194226
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 963194225}
m_Enabled: 1
--- !u!20 &963194227
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 963194225}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 1
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_GateFitMode: 2
m_FocalLength: 50
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 0
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 3
m_HDR: 1
m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &963194228
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 963194225}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10}
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}

+ 7
- 0
Assets/Scenes/SampleScene.unity.meta Ver fichero

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9fc0d4010bbf28b4594072e72b8655ab
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 373
- 0
Assets/Scenes/Start.unity Ver fichero

@@ -0,0 +1,373 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 3
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
m_GIWorkflowMode: 1
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 0
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 0
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 500
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 500
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 2
m_PVRDenoiserTypeDirect: 0
m_PVRDenoiserTypeIndirect: 0
m_PVRDenoiserTypeAO: 0
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 0
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_LightingSettings: {fileID: 315771890}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 2
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!850595691 &315771890
LightingSettings:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Settings.lighting
serializedVersion: 3
m_GIWorkflowMode: 1
m_EnableBakedLightmaps: 0
m_EnableRealtimeLightmaps: 0
m_RealtimeEnvironmentLighting: 1
m_BounceScale: 1
m_AlbedoBoost: 1
m_IndirectOutputScale: 1
m_UsingShadowmask: 1
m_BakeBackend: 0
m_LightmapMaxSize: 1024
m_BakeResolution: 40
m_Padding: 2
m_TextureCompression: 1
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAO: 0
m_MixedBakeMode: 2
m_LightmapsBakeMode: 1
m_FilterMode: 1
m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0}
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_RealtimeResolution: 2
m_ForceWhiteAlbedo: 0
m_ForceUpdates: 0
m_FinalGather: 0
m_FinalGatherRayCount: 256
m_FinalGatherFiltering: 1
m_PVRCulling: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 500
m_PVREnvironmentSampleCount: 500
m_PVREnvironmentReferencePointCount: 2048
m_LightProbeSampleCountMultiplier: 4
m_PVRBounces: 2
m_PVRMinBounces: 2
m_PVREnvironmentMIS: 0
m_PVRFilteringMode: 2
m_PVRDenoiserTypeDirect: 0
m_PVRDenoiserTypeIndirect: 0
m_PVRDenoiserTypeAO: 0
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
--- !u!1 &564699633
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 564699635}
- component: {fileID: 564699634}
m_Layer: 0
m_Name: Init
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &564699634
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 564699633}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4f155601221f7e24ab1909afd0e4121a, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UniWebView: {fileID: 776194971}
--- !u!4 &564699635
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 564699633}
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: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &776194971 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 114939446366399424, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
m_PrefabInstance: {fileID: 783622082}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 598e18fb001004a81960f552978ecf4e, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1001 &783622082
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_RootOrder
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 114939446366399424, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: urlOnStart
value: http://120.79.156.64/games/16game/
objectReference: {fileID: 0}
- target: {fileID: 114939446366399424, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: useEmbeddedToolbar
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
--- !u!1 &1313296981
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1313296986}
- component: {fileID: 1313296985}
- component: {fileID: 1313296982}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!81 &1313296982
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1313296981}
m_Enabled: 1
--- !u!20 &1313296985
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1313296981}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 1
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_FocalLength: 50
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 1
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 3
m_HDR: 1
m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &1313296986
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1313296981}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: -10}
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}

+ 7
- 0
Assets/Scenes/Start.unity.meta Ver fichero

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c02c34e4bd6e14b4784558ce2e6af62a
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 9
- 0
Assets/UniWebView.meta Ver fichero

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 92454175c62504ab5bf7128917b56362
folderAsset: yes
timeCreated: 1490878496
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

+ 1697
- 0
Assets/UniWebView/CHANGELOG.md
La diferencia del archivo ha sido suprimido porque es demasiado grande
Ver fichero


+ 8
- 0
Assets/UniWebView/CHANGELOG.md.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f7ee8c3eb642344b08f4ceeb53d70cd1
timeCreated: 1497057465
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

+ 9
- 0
Assets/UniWebView/Demo.meta Ver fichero

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 565d674726c3d499cade2709dd955ad0
folderAsset: yes
timeCreated: 1536753564
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

+ 318
- 0
Assets/UniWebView/Demo/UniWebViewDemo.unity Ver fichero

@@ -0,0 +1,318 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 3
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
m_GIWorkflowMode: 1
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 0
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 0
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 500
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 500
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 2
m_PVRDenoiserTypeDirect: 0
m_PVRDenoiserTypeIndirect: 0
m_PVRDenoiserTypeAO: 0
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 0
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_LightingSettings: {fileID: 315771890}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 2
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!850595691 &315771890
LightingSettings:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Settings.lighting
serializedVersion: 3
m_GIWorkflowMode: 1
m_EnableBakedLightmaps: 0
m_EnableRealtimeLightmaps: 0
m_RealtimeEnvironmentLighting: 1
m_BounceScale: 1
m_AlbedoBoost: 1
m_IndirectOutputScale: 1
m_UsingShadowmask: 1
m_BakeBackend: 0
m_LightmapMaxSize: 1024
m_BakeResolution: 40
m_Padding: 2
m_TextureCompression: 1
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAO: 0
m_MixedBakeMode: 2
m_LightmapsBakeMode: 1
m_FilterMode: 1
m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0}
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_RealtimeResolution: 2
m_ForceWhiteAlbedo: 0
m_ForceUpdates: 0
m_FinalGather: 0
m_FinalGatherRayCount: 256
m_FinalGatherFiltering: 1
m_PVRCulling: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 500
m_PVREnvironmentSampleCount: 500
m_PVREnvironmentReferencePointCount: 2048
m_LightProbeSampleCountMultiplier: 4
m_PVRBounces: 2
m_PVRMinBounces: 2
m_PVREnvironmentMIS: 0
m_PVRFilteringMode: 2
m_PVRDenoiserTypeDirect: 0
m_PVRDenoiserTypeIndirect: 0
m_PVRDenoiserTypeAO: 0
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
--- !u!1001 &783622082
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_RootOrder
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4960404783511462, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 114939446366399424, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: urlOnStart
value: http://120.79.156.64/games/16game/
objectReference: {fileID: 0}
- target: {fileID: 114939446366399424, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
propertyPath: useEmbeddedToolbar
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 7e3f16a6f6303419cbd9837f6c746de4, type: 3}
--- !u!1 &1313296981
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1313296986}
- component: {fileID: 1313296985}
- component: {fileID: 1313296982}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!81 &1313296982
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1313296981}
m_Enabled: 1
--- !u!20 &1313296985
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1313296981}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 1
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_FocalLength: 50
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 1
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 3
m_HDR: 1
m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &1313296986
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1313296981}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: -10}
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}

+ 8
- 0
Assets/UniWebView/Demo/UniWebViewDemo.unity.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 938c077f40a814d4584ce2ad17947cf3
timeCreated: 1536753573
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

+ 8
- 0
Assets/UniWebView/Editor.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5f0047c1c8c8348de9d66b0496b353e1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 237
- 0
Assets/UniWebView/Editor/AndroidManifest.cs Ver fichero

@@ -0,0 +1,237 @@
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");
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) {
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;
}
}

+ 11
- 0
Assets/UniWebView/Editor/AndroidManifest.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d09054fcc76964295a49868566075973
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 346
- 0
Assets/UniWebView/Editor/BuildGradle.cs Ver fichero

@@ -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;
}
}


+ 11
- 0
Assets/UniWebView/Editor/BuildGradle.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4a73a3268e19f44f7be818c5db9af457
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 47
- 0
Assets/UniWebView/Editor/GradleProperty.cs Ver fichero

@@ -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();
}
}

+ 11
- 0
Assets/UniWebView/Editor/GradleProperty.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 62bf94600ac0f42c09fc261d7ab19e12
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 15
- 0
Assets/UniWebView/Editor/UniWebView-CSharp.Editor.asmdef Ver fichero

@@ -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
- 0
Assets/UniWebView/Editor/UniWebView-CSharp.Editor.asmdef.meta Ver fichero

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b6d0e5b49a073436cbcd56804553ee20
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 219
- 0
Assets/UniWebView/Editor/UniWebViewEditorSettings.cs Ver fichero

@@ -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
- 0
Assets/UniWebView/Editor/UniWebViewEditorSettings.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a403a09e241a0480a957591ea60fb785
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 337
- 0
Assets/UniWebView/Editor/UniWebViewPostBuildProcessor.cs Ver fichero

@@ -0,0 +1,337 @@

// #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 UnityEditor;
using UnityEditor.Android;
using UnityEngine;
using System.IO;
using System.Text;

class UniWebViewPostBuildProcessor : IPostGenerateGradleAndroidProject
{
public int callbackOrder { get { return 1; } }
public void OnPostGenerateGradleAndroidProject(string path) {
Debug.Log("<UniWebView> UniWebView Post Build Scirpt 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
- 0
Assets/UniWebView/Editor/UniWebViewPostBuildProcessor.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 59d4a8d85c95843719d8b9df823c3da3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 9
- 0
Assets/UniWebView/Interface.meta Ver fichero

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: dc0f52a2d219347b1a6390b753d6ac97
folderAsset: yes
timeCreated: 1491898971
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

+ 568
- 0
Assets/UniWebView/Interface/UniWebViewAndroid.cs Ver fichero

@@ -0,0 +1,568 @@
#if UNITY_ANDROID && !UNITY_EDITOR

using UnityEngine;

class UniWebViewMethodChannel: AndroidJavaProxy
{
public UniWebViewMethodChannel() : base("com.onevcat.uniwebview.UniWebViewNativeChannel") { }

string invokeChannelMethod(string name, string method, string parameters) {
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 SetCookie(string url, string cookie, bool skipEncoding) {
CheckPlatform();
plugin.CallStatic("setCookie", url, cookie);
}

public static string GetCookie(string url, string key, bool skipEncoding) {
CheckPlatform();
return plugin.CallStatic<string>("getCookie", url, key);
}

public static void RemoveCookies(string url, bool skipEncoding) {
CheckPlatform();
plugin.CallStatic("removeCookies", url);
}

public static void RemoveCookie(string url, string key, bool skipEncoding) {
CheckPlatform();
plugin.CallStatic("removeCookie", url, key);
}

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

+ 12
- 0
Assets/UniWebView/Interface/UniWebViewAndroid.cs.meta Ver fichero

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5a1d3cecc27d64565835e14b493c935b
timeCreated: 1490880130
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 40
- 0
Assets/UniWebView/Interface/UniWebViewAndroidStaticListener.cs Ver fichero

@@ -0,0 +1,40 @@

// #if UNITY_ANDROID && !UNITY_EDITOR
using System;
using System.Reflection;
using UnityEngine;

public class UniWebViewAndroidStaticListener: MonoBehaviour {
void Awake() {
DontDestroyOnLoad(gameObject);
}

void OnJavaMessage(string 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
- 0
Assets/UniWebView/Interface/UniWebViewAndroidStaticListener.cs.meta Ver fichero

@@ -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:

+ 898
- 0
Assets/UniWebView/Interface/UniWebViewCocoa.cs Ver fichero

@@ -0,0 +1,898 @@
//
// 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 = "UniWebView-static";
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) {
MethodInfo methodInfo = typeof(UniWebViewStaticListener)
.GetMethod(method, BindingFlags.Static | BindingFlags.Public);
methodInfo.Invoke(null, new object[] { parameters });
return;
}
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);

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_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_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_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 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_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_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

+ 12
- 0
Assets/UniWebView/Interface/UniWebViewCocoa.cs.meta Ver fichero

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 2e905ba0b47304f4cbf9e3e3345f84eb
timeCreated: 1492400358
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 113
- 0
Assets/UniWebView/Interface/UniWebViewPlaceholder.cs Ver fichero

@@ -0,0 +1,113 @@
#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 SetCookie(string url, string cookie, bool skipEncoding) { CheckPlatform(); }
public static void RemoveCookies(string url, bool skipEncoding) { CheckPlatform(); }
public static void RemoveCookie(string url, string key, bool skipEncoding) { CheckPlatform(); }
public static string GetCookie(string url, string key, bool skipEncoding) { CheckPlatform(); return ""; }
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
- 0
Assets/UniWebView/Interface/UniWebViewPlaceholder.cs.meta Ver fichero

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0b3bad20d12b1433ab8927c3effc605b
timeCreated: 1497403102
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 9
- 0
Assets/UniWebView/Prefab.meta Ver fichero

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: d5d657f2ee1114e20bccaace74235a99
folderAsset: yes
timeCreated: 1491898971
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

+ 60
- 0
Assets/UniWebView/Prefab/UniWebView.prefab Ver fichero

@@ -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}

+ 9
- 0
Assets/UniWebView/Prefab/UniWebView.prefab.meta Ver fichero

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 7e3f16a6f6303419cbd9837f6c746de4
timeCreated: 1496204510
licenseType: Store
NativeFormatImporter:
mainObjectFileID: 100100000
userData:
assetBundleName:
assetBundleVariant:

+ 46
- 0
Assets/UniWebView/Prefab/UniWebViewSafeBrowsing.prefab Ver fichero

@@ -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
- 0
Assets/UniWebView/Prefab/UniWebViewSafeBrowsing.prefab.meta Ver fichero

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2d6c4899a63004f16bb4f791176f4ad3
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 30
- 0
Assets/UniWebView/README.txt Ver fichero

@@ -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.

+ 8
- 0
Assets/UniWebView/README.txt.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 95440ce70c5e14d6e96e166c45f7cf6d
timeCreated: 1499302025
licenseType: Store
TextScriptImporter:
userData:
assetBundleName:
assetBundleVariant:

+ 9
- 0
Assets/UniWebView/Script.meta Ver fichero

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: b34f36f9836464e04893f632434d0862
folderAsset: yes
timeCreated: 1491898971
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

+ 8
- 0
Assets/UniWebView/Script/External.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 43c2ab2efc7244e0293d0a1cb0d869e8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 551
- 0
Assets/UniWebView/Script/External/MiniJSON.cs Ver fichero

@@ -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&lt;object&gt;, a Dictionary&lt;string, object&gt;, 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&lt;string, object&gt; / List&lt;object&gt;</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());
}
}
}
}
}

+ 11
- 0
Assets/UniWebView/Script/External/MiniJSON.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f11796a30129b4c71aa6a52d59c6be19
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 2242
- 0
Assets/UniWebView/Script/UniWebView.cs
La diferencia del archivo ha sido suprimido porque es demasiado grande
Ver fichero


+ 12
- 0
Assets/UniWebView/Script/UniWebView.cs.meta Ver fichero

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 598e18fb001004a81960f552978ecf4e
timeCreated: 1491898971
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 8
- 0
Assets/UniWebView/Script/UniWebViewAuthentication.meta Ver fichero

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5b17dc622ffd649da85854192714e429
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

+ 94
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationCommonFlow.cs Ver fichero

@@ -0,0 +1,94 @@
//
// 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;
}
}
}

+ 11
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationCommonFlow.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6bfa5bb9dc237400298563d614b62705
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 356
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlow.cs Ver fichero

@@ -0,0 +1,356 @@
//
// 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 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;

public UniWebViewAuthenticationFlow(
IUniWebViewAuthenticationFlow<TTokenType> service
)
{
this.service = service;
}

/// <summary>
/// Start the authentication flow.
/// </summary>
public void StartAuth()
{
var callbackUri = new Uri(service.GetCallbackUrl());
var authUrl = GetAuthUrl();
var session = UniWebViewAuthenticationSession.Create(authUrl, callbackUri.Scheme);
var flow = service as UniWebViewAuthenticationCommonFlow;
if (flow != null && flow.privateMode) {
session.SetPrivateMode(true);
}
session.OnAuthenticationFinished += (_, resultUrl) => {
UniWebViewLogger.Instance.Verbose("Auth flow received callback url: " + resultUrl);
ExchangeToken(resultUrl);
};

session.OnAuthenticationErrorReceived += (_, errorCode, message) => {
ExchangeTokenErrored(errorCode, message);
};
UniWebViewLogger.Instance.Verbose("Starting auth flow with url: " + authUrl + "; Callback scheme: " + callbackUri.Scheme);
session.Start();
}

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);
}
builder.Query = UniWebViewAuthenticationUtils.CreateQueryString(query);
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);
}
}

+ 11
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlow.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4add539e6d306455c9da09b069e248bd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 230
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowCustomize.cs Ver fichero

@@ -0,0 +1,230 @@
//
// 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;
}

/// <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 = "";
}

+ 11
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowCustomize.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bfcc799dc1a0c4ef58bc3486a8af7afa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 222
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowDiscord.cs Ver fichero

@@ -0,0 +1,222 @@
//
// 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;
}

/// <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 token object from Discord. Check `UniWebViewAuthenticationStandardToken` for more.
/// </summary>
public class UniWebViewAuthenticationDiscordToken : UniWebViewAuthenticationStandardToken { }


+ 11
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowDiscord.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 69ed5d1df2635470ca5c939d11d16924
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 217
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowFacebook.cs Ver fichero

@@ -0,0 +1,217 @@
//
// 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);
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 = "";
}

/// 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;
}
}


+ 11
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowFacebook.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ba2d51a8adc8e42b4aaff50218dfe058
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 255
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowGitHub.cs Ver fichero

@@ -0,0 +1,255 @@
//
// 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");
}
}

return authorizeArgs;
}

/// <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 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;
}
}

+ 11
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowGitHub.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1925cdd8b9d284ec48146d7d03c41672
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 231
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowGoogle.cs Ver fichero

@@ -0,0 +1,231 @@
//
// 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);
}
}

return authorizeArgs;
}

/// <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 token object from Google. Check `UniWebViewAuthenticationStandardToken` for more.
/// </summary>
public class UniWebViewAuthenticationGoogleToken : UniWebViewAuthenticationStandardToken { }


+ 3
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowGoogle.cs.meta Ver fichero

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9a51fd6394dc49ed954d995b9f7b0bbc
timeCreated: 1655992593

+ 227
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowLine.cs Ver fichero

@@ -0,0 +1,227 @@
//
// 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;
}

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);
}
}
return "/oauth2/v2.1/authorize/consent?" + UniWebViewAuthenticationUtils.CreateQueryString(query);
}

/// <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 token object from LINE. Check `UniWebViewAuthenticationStandardToken` for more.
/// </summary>
public class UniWebViewAuthenticationLineToken : UniWebViewAuthenticationStandardToken { }

+ 11
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowLine.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 69f3e0ea73db84403850bcdbc6531a62
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 211
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowTwitter.cs Ver fichero

@@ -0,0 +1,211 @@
//
// 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;
}

/// <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 token object from Twitter. Check `UniWebViewAuthenticationStandardToken` for more.
/// </summary>
public class UniWebViewAuthenticationTwitterToken : UniWebViewAuthenticationStandardToken { }

+ 11
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationFlowTwitter.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 86840692470304a76b6d2ac73771b7af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 182
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationSession.cs Ver fichero

@@ -0,0 +1,182 @@
//
// 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>
/// 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);
}
}

+ 11
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationSession.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e5e52f46b3fba4e1c868230b0da9fd5f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 116
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationStandardToken.cs Ver fichero

@@ -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;
}
}

+ 3
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationStandardToken.cs.meta Ver fichero

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bda3fe59d0bb48c890f1545b0b22dee4
timeCreated: 1656308530

+ 198
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationUtils.cs Ver fichero

@@ -0,0 +1,198 @@
//
// 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) {
int count = collection.Count;
if (count == 0) {
return "";
}
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) {
sb.Length--;
}
return sb.ToString();
}
}

public enum UniWebViewAuthenticationPKCE
{
None,
S256,
Plain
}

+ 11
- 0
Assets/UniWebView/Script/UniWebViewAuthentication/UniWebViewAuthenticationUtils.cs.meta Ver fichero

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cb86a1823d1e54d558d6f77e3c36719b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 45
- 0
Assets/UniWebView/Script/UniWebViewCacheMode.cs Ver fichero

@@ -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,
}

+ 3
- 0
Assets/UniWebView/Script/UniWebViewCacheMode.cs.meta Ver fichero

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: af9091341ad1451a88060e20c2dc953f
timeCreated: 1705494877

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio

Cargando…
Cancelar
Guardar