diff --git a/.gitignore b/.gitignore index c5a0afab..baff6671 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ Temp *.sln *.pidb *.userprefs +**/*.xcodeproj/* +!**/*.xcodeproj/project.pbxproj +!**/*.xcworkspace/contents.xcworkspacedata diff --git a/README.md b/README.md index ff27081c..f89d1723 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ below: ### OS X (Editor) +#### App Transport Security + Since Unity 5.3.0, Unity.app is built with ATS (App Transport Security) enabled and non-secured connection (HTTP) is not permitted. If you want to open `http://foo/bar.html` with this plugin @@ -50,11 +52,19 @@ or invoke the following from your terminal, /usr/libexec/PlistBuddy -c "Add NSAppTransportSecurity:NSAllowsArbitraryLoads bool true" /Applications/Unity/Unity.app/Contents/Info.plist ``` -#### References +##### References * https://github.com/gree/unity-webview/issues/64 * https://onevcat.zendesk.com/hc/en-us/articles/215527307-I-cannot-open-the-web-page-in-Unity-Editor- +#### WebViewSeparated.bundle + +WebViewSeparated.bundle is a variation of WebView.bundle. It is based +on https://github.com/gree/unity-webview/pull/161 . As noted in the +pull-request, it shows a separate window and allows a developer to +utilize the Safari debugger. For enabling it, please define +`WEBVIEW_SEPARATED`. + ### iOS The implementation now supports WKWebView but it is disabled by diff --git a/dist/unity-webview.unitypackage b/dist/unity-webview.unitypackage index 30b6379f..1c07d011 100644 Binary files a/dist/unity-webview.unitypackage and b/dist/unity-webview.unitypackage differ diff --git a/dist/unity-webview.zip b/dist/unity-webview.zip index 9073869b..008e1372 100644 Binary files a/dist/unity-webview.zip and b/dist/unity-webview.zip differ diff --git a/plugins/Mac/Resources/Info-WebViewSeparated.plist b/plugins/Mac/Resources/Info-WebViewSeparated.plist new file mode 100644 index 00000000..e89822fe --- /dev/null +++ b/plugins/Mac/Resources/Info-WebViewSeparated.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/plugins/Mac/Resources/Info.plist b/plugins/Mac/Resources/Info.plist index 2dc923d6..e89822fe 100644 --- a/plugins/Mac/Resources/Info.plist +++ b/plugins/Mac/Resources/Info.plist @@ -9,7 +9,7 @@ CFBundleIconFile CFBundleIdentifier - net.gree.unitywebview.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/plugins/Mac/Sources/WebView.m b/plugins/Mac/Sources/WebView.m index 8da64473..cd9db72a 100644 --- a/plugins/Mac/Sources/WebView.m +++ b/plugins/Mac/Sources/WebView.m @@ -1,15 +1,15 @@ /* * Copyright (C) 2011 Keijiro Takahashi * Copyright (C) 2012 GREE, Inc. - * + * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. - * + * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: - * + * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be @@ -34,20 +34,20 @@ typedef void *MonoMethod; typedef void *MonoString; +#ifdef __cplusplus extern "C" { +#endif MonoDomain *mono_domain_get(); - MonoAssembly *mono_domain_assembly_open( - MonoDomain *domain, const char *assemblyName); + MonoAssembly *mono_domain_assembly_open(MonoDomain *domain, const char *assemblyName); MonoImage *mono_assembly_get_image(MonoAssembly *assembly); - MonoMethodDesc *mono_method_desc_new( - const char *methodString, int useNamespace); + MonoMethodDesc *mono_method_desc_new(const char *methodString, int useNamespace); MonoMethodDesc *mono_method_desc_free(MonoMethodDesc *desc); - MonoMethod *mono_method_desc_search_in_image( - MonoMethodDesc *methodDesc, MonoImage *image); - MonoObject *mono_runtime_invoke( - MonoMethod *method, void *obj, void **params, MonoObject **exc); + MonoMethod *mono_method_desc_search_in_image(MonoMethodDesc *methodDesc, MonoImage *image); + MonoObject *mono_runtime_invoke(MonoMethod *method, void *obj, void **params, MonoObject **exc); MonoString *mono_string_new(MonoDomain *domain, const char *text); +#ifdef __cplusplus } +#endif static BOOL inEditor; static MonoDomain *monoDomain; @@ -73,7 +73,7 @@ static void UnitySendMessage( monoDomain = mono_domain_get(); monoDesc = mono_method_desc_new( "UnitySendMessageDispatcher:Dispatch(string,string,string)", FALSE); - + monoAssembly = mono_domain_assembly_open(monoDomain, [assemblyPath UTF8String]); @@ -81,8 +81,8 @@ static void UnitySendMessage( monoImage = mono_assembly_get_image(monoAssembly); monoMethod = mono_method_desc_search_in_image(monoDesc, monoImage); } - - + + if (monoMethod == 0) { if (inEditor) { assemblyPath = @@ -102,11 +102,11 @@ static void UnitySendMessage( } } } - + if (monoMethod == 0) { return; } - + void *args[] = { mono_string_new(monoDomain, gameObject), mono_string_new(monoDomain, method), @@ -196,7 +196,7 @@ - (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary } else { if ([customRequestHeader count] > 0) { bool isCustomized = YES; - + // Check for additional custom header. for (NSString *key in [customRequestHeader allKeys]) { @@ -213,7 +213,7 @@ - (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary return; } } - + [listener use]; } } @@ -321,20 +321,20 @@ - (void)update:(int)x y:(int)y deltaY:(float)deltaY buttonDown:(BOOL)buttonDown event = [NSEvent mouseEventWithType:NSLeftMouseDown location:NSMakePoint(x, y) modifierFlags:nil timestamp:GetCurrentEventTime() windowNumber:0 - context:context eventNumber:nil clickCount:1 pressure:nil]; + context:context eventNumber:nil clickCount:1 pressure:1]; [view mouseDown:event]; } else { event = [NSEvent mouseEventWithType:NSLeftMouseDragged location:NSMakePoint(x, y) modifierFlags:nil timestamp:GetCurrentEventTime() windowNumber:0 - context:context eventNumber:nil clickCount:0 pressure:nil]; + context:context eventNumber:nil clickCount:0 pressure:1]; [view mouseDragged:event]; } } else if (buttonRelease) { event = [NSEvent mouseEventWithType:NSLeftMouseUp location:NSMakePoint(x, y) modifierFlags:nil timestamp:GetCurrentEventTime() windowNumber:0 - context:context eventNumber:nil clickCount:0 pressure:nil]; + context:context eventNumber:nil clickCount:0 pressure:0]; [view mouseUp:event]; } @@ -452,7 +452,7 @@ - (const char *)getCustomRequestHeaderValue:(const char *)headerKey if (!result) { return NULL; } - + const char *s = [result UTF8String]; char *r = (char *)malloc(strlen(s) + 1); strcpy(r, s); @@ -462,7 +462,9 @@ - (const char *)getCustomRequestHeaderValue:(const char *)headerKey @end typedef void (*UnityRenderEventFunc)(int eventId); +#ifdef __cplusplus extern "C" { +#endif const char *_CWebViewPlugin_GetAppPath(); void *_CWebViewPlugin_Init( const char *gameObject, BOOL transparent, int width, int height, const char *ua, BOOL ineditor); @@ -489,7 +491,9 @@ void _CWebViewPlugin_Update(void *instance, int x, int y, float deltaY, void _CWebViewPlugin_RemoveCustomHeader(void *instance, const char *headerKey); void _CWebViewPlugin_ClearCustomHeader(void *instance); const char *_CWebViewPlugin_GetCustomHeaderValue(void *instance, const char *headerKey); +#ifdef __cplusplus } +#endif const char *_CWebViewPlugin_GetAppPath() { diff --git a/plugins/Mac/Sources/WebViewSeparated.m b/plugins/Mac/Sources/WebViewSeparated.m new file mode 100644 index 00000000..b2928a3a --- /dev/null +++ b/plugins/Mac/Sources/WebViewSeparated.m @@ -0,0 +1,755 @@ +/* + * Copyright (C) 2011 Keijiro Takahashi + * Copyright (C) 2012 GREE, Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#import +#import +#import +#import +#import +#import + +typedef void *MonoDomain; +typedef void *MonoAssembly; +typedef void *MonoImage; +typedef void *MonoObject; +typedef void *MonoMethodDesc; +typedef void *MonoMethod; +typedef void *MonoString; + +#ifdef __cplusplus +extern "C" { +#endif + MonoDomain *mono_domain_get(); + MonoAssembly *mono_domain_assembly_open(MonoDomain *domain, const char *assemblyName); + MonoImage *mono_assembly_get_image(MonoAssembly *assembly); + MonoMethodDesc *mono_method_desc_new(const char *methodString, int useNamespace); + MonoMethodDesc *mono_method_desc_free(MonoMethodDesc *desc); + MonoMethod *mono_method_desc_search_in_image(MonoMethodDesc *methodDesc, MonoImage *image); + MonoObject *mono_runtime_invoke(MonoMethod *method, void *obj, void **params, MonoObject **exc); + MonoString *mono_string_new(MonoDomain *domain, const char *text); +#ifdef __cplusplus +} +#endif + +static BOOL inEditor; +static MonoDomain *monoDomain; +static MonoAssembly *monoAssembly; +static MonoImage *monoImage; +static MonoMethodDesc *monoDesc; +static MonoMethod *monoMethod; + +static void UnitySendMessage( + const char *gameObject, const char *method, const char *message) +{ + if (monoMethod == 0) { + NSString *assemblyPath; + if (inEditor) { + assemblyPath = + @"Library/ScriptAssemblies/Assembly-CSharp-firstpass.dll"; + } else { + NSString *dllPath = + @"Contents/Resources/Data/Managed/Assembly-CSharp-firstpass.dll"; + assemblyPath = [[[NSBundle mainBundle] bundlePath] + stringByAppendingPathComponent:dllPath]; + } + monoDomain = mono_domain_get(); + monoDesc = mono_method_desc_new( + "UnitySendMessageDispatcher:Dispatch(string,string,string)", FALSE); + + monoAssembly = + mono_domain_assembly_open(monoDomain, [assemblyPath UTF8String]); + + if (monoAssembly != 0) { + monoImage = mono_assembly_get_image(monoAssembly); + monoMethod = mono_method_desc_search_in_image(monoDesc, monoImage); + } + + + if (monoMethod == 0) { + if (inEditor) { + assemblyPath = + @"Library/ScriptAssemblies/Assembly-CSharp.dll"; + } else { + NSString *dllPath = + @"Contents/Resources/Data/Managed/Assembly-CSharp.dll"; + assemblyPath = [[[NSBundle mainBundle] bundlePath] + stringByAppendingPathComponent:dllPath]; + } + monoAssembly = + mono_domain_assembly_open(monoDomain, [assemblyPath UTF8String]); + + if (monoAssembly != 0) { + monoImage = mono_assembly_get_image(monoAssembly); + monoMethod = mono_method_desc_search_in_image(monoDesc, monoImage); + } + } + } + + if (monoMethod == 0) { + return; + } + + void *args[] = { + mono_string_new(monoDomain, gameObject), + mono_string_new(monoDomain, method), + mono_string_new(monoDomain, message), + }; + + mono_runtime_invoke(monoMethod, 0, args, 0); +} + +@interface CWebViewPlugin : NSObject +{ + NSWindow *window; + NSWindowController *windowController; + WKWebView *webView; + NSString *gameObject; + NSString *ua; + NSBitmapImageRep *bitmap; + int textureId; + BOOL needsDisplay; + NSMutableDictionary *customRequestHeader; +} +@end + +@implementation CWebViewPlugin + +- (id)initWithGameObject:(const char *)gameObject_ transparent:(BOOL)transparent width:(int)width height:(int)height ua:(const char *)ua_ +{ + self = [super init]; + monoMethod = 0; + customRequestHeader = [[NSMutableDictionary alloc] init]; + + WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; + WKUserContentController *controller = [[WKUserContentController alloc] init]; + WKPreferences *preferences = [[WKPreferences alloc] init]; + preferences.javaScriptEnabled = true; + preferences.plugInsEnabled = true; + [controller addScriptMessageHandler:self name:@"unityControl"]; + configuration.userContentController = controller; + // configuration.preferences = preferences; + NSRect frame = NSMakeRect(0, 0, width / 2, height / 2); + webView = [[WKWebView alloc] initWithFrame:frame + configuration:configuration]; + [[[webView configuration] preferences] setValue:@YES forKey:@"developerExtrasEnabled"]; + webView.UIDelegate = self; + webView.navigationDelegate = self; + webView.hidden = NO; + if (transparent) { + // [webView setDrawsBackground:NO]; + } + [webView setAutoresizingMask:(NSViewWidthSizable|NSViewHeightSizable)]; + // [webView setFrameLoadDelegate:(id)self]; + // [webView setPolicyDelegate:(id)self]; + webView.UIDelegate = self; + webView.navigationDelegate = self; + gameObject = [[NSString stringWithUTF8String:gameObject_] retain]; + if (ua_ != NULL && strcmp(ua_, "") != 0) { + ua = [[NSString stringWithUTF8String:ua_] retain]; + [webView setCustomUserAgent:ua]; + } + + window = [[[NSWindow alloc] initWithContentRect:frame + styleMask:NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskResizable + backing:NSBackingStoreBuffered + defer:NO] autorelease]; + [window setContentView:webView]; + [window orderFront:NSApp]; + windowController = [[NSWindowController alloc] initWithWindow:window]; + + return self; +} + +- (void)dealloc +{ + @synchronized(self) { + if (webView != nil) { + // [webView setFrameLoadDelegate:nil]; + // [webView setPolicyDelegate:nil]; + webView.UIDelegate = nil; + webView.navigationDelegate = nil; + [webView stopLoading:nil]; + [webView release]; + webView = nil; + } + if (gameObject != nil) { + [gameObject release]; + gameObject = nil; + } + if (ua != nil) { + [ua release]; + ua = nil; + } + if (bitmap != nil) { + [bitmap release]; + bitmap = nil; + } + if (window != nil) { + [window release]; + window = nil; + } + if (windowController != nil){ + [windowController release]; + windowController = nil; + } + } + [super dealloc]; +} + + +/* +- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame +{ + UnitySendMessage([gameObject UTF8String], "CallOnError", [[error description] UTF8String]); +} + +- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame +{ + UnitySendMessage([gameObject UTF8String], "CallOnLoaded", [[[[[frame dataSource] request] URL] absoluteString] UTF8String]); +} + +- (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener +{ + NSString *url = [[request URL] absoluteString]; + if ([url hasPrefix:@"unity:"]) { + UnitySendMessage([gameObject UTF8String], "CallFromJS", [[url substringFromIndex:6] UTF8String]); + [listener ignore]; + } else { + if ([customRequestHeader count] > 0) { + bool isCustomized = YES; + + // Check for additional custom header. + for (NSString *key in [customRequestHeader allKeys]) + { + if (![[[request allHTTPHeaderFields] objectForKey:key] isEqualToString:[customRequestHeader objectForKey:key]]) { + isCustomized = NO; + break; + } + } + + // If the custom header is not attached, give it and make a request again. + if (!isCustomized) { + [listener ignore]; + [frame loadRequest:[self constructionCustomHeader:request]]; + return; + } + } + + [listener use]; + } +} +*/ + +- (void)webView:(WKWebView*)wkWebView didCommitNavigation:(null_unspecified WKNavigation *)navigation +{ + UnitySendMessage([gameObject UTF8String], "CallOnLoaded", "Unknown URL"); + +} + +- (void)webView:(WKWebView *)wkWebView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler +{ + if (webView == nil) { + decisionHandler(WKNavigationActionPolicyCancel); + return; + } + NSURL *url = [navigationAction.request URL]; + //if ([url.absoluteString rangeOfString:@"//itunes.apple.com/"].location != NSNotFound) { + // [[UIApplication sharedApplication] openURL:url]; + // decisionHandler(WKNavigationActionPolicyCancel); + //} else + if ([url.absoluteString hasPrefix:@"unity:"]) { + UnitySendMessage([gameObject UTF8String], "CallFromJS", [[url.absoluteString substringFromIndex:6] UTF8String]); + decisionHandler(WKNavigationActionPolicyCancel); + } else if (navigationAction.navigationType == WKNavigationTypeLinkActivated + && (!navigationAction.targetFrame || !navigationAction.targetFrame.isMainFrame)) { + // cf. for target="_blank", cf. http://qiita.com/ShingoFukuyama/items/b3a1441025a36ab7659c + [webView loadRequest:navigationAction.request]; + decisionHandler(WKNavigationActionPolicyCancel); + } else { + decisionHandler(WKNavigationActionPolicyAllow); + } +} + + +- (void)userContentController:(WKUserContentController *)userContentController + didReceiveScriptMessage:(WKScriptMessage *)message { + + // Log out the message received + NSLog(@"Received event %@", message.body); + UnitySendMessage([gameObject UTF8String], "CallFromJS", + [[NSString stringWithFormat:@"%@", message.body] UTF8String]); + + /* + // Then pull something from the device using the message body + NSString *version = [[UIDevice currentDevice] valueForKey:message.body]; + + // Execute some JavaScript using the result? + NSString *exec_template = @"set_headline(\"received: %@\");"; + NSString *exec = [NSString stringWithFormat:exec_template, version]; + [webView evaluateJavaScript:exec completionHandler:nil]; + */ +} + +- (void)setRect:(int)width height:(int)height +{ + if (webView == nil) + return; + NSRect frame; + frame.size.width = width / 2; + frame.size.height = height / 2; + frame.origin.x = 0; + frame.origin.y = 0; + webView.frame = frame; + if (bitmap != nil) { + [bitmap release]; + bitmap = nil; + } +} + +- (void)setVisibility:(BOOL)visibility +{ + if (webView == nil) + return; + // webView.hidden = visibility ? NO : YES; +} + +- (NSURLRequest *)constructionCustomHeader:(NSURLRequest *)originalRequest +{ + NSMutableURLRequest *convertedRequest = originalRequest.mutableCopy; + for (NSString *key in [customRequestHeader allKeys]) { + [convertedRequest setValue:customRequestHeader[key] forHTTPHeaderField:key]; + } + return convertedRequest; +} + +- (void)loadURL:(const char *)url +{ + if (webView == nil) + return; + NSString *urlStr = [NSString stringWithUTF8String:url]; + NSURL *nsurl = [NSURL URLWithString:urlStr]; + NSURLRequest *request = [NSURLRequest requestWithURL:nsurl]; + + if ([nsurl.absoluteString hasPrefix:@"file:"]) { + NSURL *top = [NSURL URLWithString:[[nsurl absoluteString] stringByDeletingLastPathComponent]]; + [webView loadFileURL:nsurl allowingReadAccessToURL:top]; + } else { + [webView loadRequest:request]; + } +} + +- (void)loadHTML:(const char *)html baseURL:(const char *)baseUrl +{ + if (webView == nil) + return; + NSString *htmlStr = [NSString stringWithUTF8String:html]; + NSString *baseStr = [NSString stringWithUTF8String:baseUrl]; + NSURL *baseNSUrl = [NSURL URLWithString:baseStr]; + [webView loadHTMLString:htmlStr baseURL:baseNSUrl]; +} + +- (void)evaluateJS:(const char *)js +{ + if (webView == nil) + return; + NSString *jsStr = [NSString stringWithUTF8String:js]; + [webView evaluateJavaScript:jsStr completionHandler:nil]; +} + +- (BOOL)canGoBack +{ + if (webView == nil) + return false; + return [webView canGoBack]; +} + +- (BOOL)canGoForward +{ + if (webView == nil) + return false; + return [webView canGoForward]; +} + +- (void)goBack +{ + if (webView == nil) + return; + [webView goBack]; +} + +- (void)goForward +{ + if (webView == nil) + return; + [webView goForward]; +} + +- (void)update:(int)x y:(int)y deltaY:(float)deltaY buttonDown:(BOOL)buttonDown buttonPress:(BOOL)buttonPress buttonRelease:(BOOL)buttonRelease keyPress:(BOOL)keyPress keyCode:(unsigned short)keyCode keyChars:(const char*)keyChars +{ + if (webView == nil) + return; + + NSView *view = webView; + NSGraphicsContext *context = [NSGraphicsContext currentContext]; + NSEvent *event; + NSString *characters; + + if (buttonDown) { + if (buttonPress) { + event = [NSEvent mouseEventWithType:NSLeftMouseDown + location:NSMakePoint(x, y) modifierFlags:nil + timestamp:GetCurrentEventTime() windowNumber:0 + context:context eventNumber:nil clickCount:1 pressure:1]; + [view mouseDown:event]; + } else { + event = [NSEvent mouseEventWithType:NSLeftMouseDragged + location:NSMakePoint(x, y) modifierFlags:nil + timestamp:GetCurrentEventTime() windowNumber:0 + context:context eventNumber:nil clickCount:0 pressure:1]; + [view mouseDragged:event]; + } + } else if (buttonRelease) { + event = [NSEvent mouseEventWithType:NSLeftMouseUp + location:NSMakePoint(x, y) modifierFlags:nil + timestamp:GetCurrentEventTime() windowNumber:0 + context:context eventNumber:nil clickCount:0 pressure:0]; + [view mouseUp:event]; + } + + if (keyPress) { + characters = [NSString stringWithUTF8String:keyChars]; + event = [NSEvent keyEventWithType:NSKeyDown + location:NSMakePoint(x, y) modifierFlags:nil + timestamp:GetCurrentEventTime() windowNumber:0 + context:context + characters:characters + charactersIgnoringModifiers:characters + isARepeat:NO keyCode:(unsigned short)keyCode]; + [view keyDown:event]; + } + + if (deltaY != 0) { + CGEventRef cgEvent = CGEventCreateScrollWheelEvent(NULL, + kCGScrollEventUnitLine, 1, deltaY * 3, 0); + NSEvent *scrollEvent = [NSEvent eventWithCGEvent:cgEvent]; + CFRelease(cgEvent); + [view scrollWheel:scrollEvent]; + } + + @synchronized(self) { + if (bitmap == nil) + bitmap = [[webView bitmapImageRepForCachingDisplayInRect:webView.frame] retain]; + memset([bitmap bitmapData], 0, [bitmap bytesPerRow] * [bitmap pixelsHigh]); + [webView cacheDisplayInRect:webView.frame toBitmapImageRep:bitmap]; + needsDisplay = YES; // TODO (bitmap == nil || [view needsDisplay]); + } +} + +- (int)bitmapWide +{ + @synchronized(self) { + return (bitmap == nil) ? 0 : (int)[bitmap pixelsWide]; + } +} + +- (int)bitmapHigh +{ + @synchronized(self) { + return (bitmap == nil) ? 0 : (int)[bitmap pixelsHigh]; + } +} + +- (void)setTextureId:(int)tId +{ + @synchronized(self) { + textureId = tId; + } +} + +- (void)render +{ + @synchronized(self) { + if (webView == nil) + return; + if (!needsDisplay) + return; + if (bitmap == nil) + return; + + int samplesPerPixel = (int)[bitmap samplesPerPixel]; + int rowLength = 0; + int unpackAlign = 0; + glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowLength); + glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpackAlign); + glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)[bitmap bytesPerRow] / samplesPerPixel); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glBindTexture(GL_TEXTURE_2D, textureId); + if (![bitmap isPlanar] && (samplesPerPixel == 3 || samplesPerPixel == 4)) { + glTexSubImage2D( + GL_TEXTURE_2D, + 0, + 0, + 0, + (GLsizei)[bitmap pixelsWide], + (GLsizei)[bitmap pixelsHigh], + samplesPerPixel == 4 ? GL_RGBA : GL_RGB, + GL_UNSIGNED_BYTE, + [bitmap bitmapData]); + } + glPixelStorei(GL_UNPACK_ROW_LENGTH, rowLength); + glPixelStorei(GL_UNPACK_ALIGNMENT, unpackAlign); + } +} + +- (void)addCustomRequestHeader:(const char *)headerKey value:(const char *)headerValue +{ + NSString *keyString = [NSString stringWithUTF8String:headerKey]; + NSString *valueString = [NSString stringWithUTF8String:headerValue]; + + [customRequestHeader setObject:valueString forKey:keyString]; +} + +- (void)removeCustomRequestHeader:(const char *)headerKey +{ + NSString *keyString = [NSString stringWithUTF8String:headerKey]; + + if ([[customRequestHeader allKeys]containsObject:keyString]) { + [customRequestHeader removeObjectForKey:keyString]; + } +} + +- (void)clearCustomRequestHeader +{ + [customRequestHeader removeAllObjects]; +} + +- (const char *)getCustomRequestHeaderValue:(const char *)headerKey +{ + NSString *keyString = [NSString stringWithUTF8String:headerKey]; + NSString *result = [customRequestHeader objectForKey:keyString]; + if (!result) { + return NULL; + } + + const char *s = [result UTF8String]; + char *r = (char *)malloc(strlen(s) + 1); + strcpy(r, s); + return r; +} + +@end + +typedef void (*UnityRenderEventFunc)(int eventId); +#ifdef __cplusplus +extern "C" { +#endif +const char *_CWebViewPlugin_GetAppPath(); +void *_CWebViewPlugin_Init( + const char *gameObject, BOOL transparent, int width, int height, const char *ua, BOOL ineditor); +void _CWebViewPlugin_Destroy(void *instance); +void _CWebViewPlugin_SetRect(void *instance, int width, int height); +void _CWebViewPlugin_SetVisibility(void *instance, BOOL visibility); +void _CWebViewPlugin_LoadURL(void *instance, const char *url); +void _CWebViewPlugin_LoadHTML(void *instance, const char *html, const char *baseUrl); +void _CWebViewPlugin_EvaluateJS(void *instance, const char *url); +BOOL _CWebViewPlugin_CanGoBack(void *instance); +BOOL _CWebViewPlugin_CanGoForward(void *instance); +void _CWebViewPlugin_GoBack(void *instance); +void _CWebViewPlugin_GoForward(void *instance); +void _CWebViewPlugin_Update(void *instance, int x, int y, float deltaY, + BOOL buttonDown, BOOL buttonPress, BOOL buttonRelease, + BOOL keyPress, unsigned char keyCode, const char *keyChars); +int _CWebViewPlugin_BitmapWidth(void *instance); +int _CWebViewPlugin_BitmapHeight(void *instance); +void _CWebViewPlugin_SetTextureId(void *instance, int textureId); +void _CWebViewPlugin_SetCurrentInstance(void *instance); +void UnityRenderEvent(int eventId); +UnityRenderEventFunc GetRenderEventFunc(); +void _CWebViewPlugin_AddCustomHeader(void *instance, const char *headerKey, const char *headerValue); +void _CWebViewPlugin_RemoveCustomHeader(void *instance, const char *headerKey); +void _CWebViewPlugin_ClearCustomHeader(void *instance); +const char *_CWebViewPlugin_GetCustomHeaderValue(void *instance, const char *headerKey); +#ifdef __cplusplus +} +#endif + +const char *_CWebViewPlugin_GetAppPath() +{ + const char *s = [[[[NSBundle mainBundle] bundleURL] absoluteString] UTF8String]; + char *r = (char *)malloc(strlen(s) + 1); + strcpy(r, s); + return r; +} + +static NSMutableSet *pool; + +void *_CWebViewPlugin_Init( + const char *gameObject, BOOL transparent, int width, int height, const char *ua, BOOL ineditor) +{ + if (pool == 0) + pool = [[NSMutableSet alloc] init]; + + inEditor = ineditor; + id instance = [[CWebViewPlugin alloc] initWithGameObject:gameObject transparent:transparent width:width height:height ua:ua]; + [pool addObject:[NSValue valueWithPointer:instance]]; + return (void *)instance; +} + +void _CWebViewPlugin_Destroy(void *instance) +{ + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)instance; + [webViewPlugin release]; + [pool removeObject:[NSValue valueWithPointer:instance]]; +} + +void _CWebViewPlugin_SetRect(void *instance, int width, int height) +{ + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)instance; + [webViewPlugin setRect:width height:height]; +} + +void _CWebViewPlugin_SetVisibility(void *instance, BOOL visibility) +{ + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)instance; + [webViewPlugin setVisibility:visibility]; +} + +void _CWebViewPlugin_LoadURL(void *instance, const char *url) +{ + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)instance; + [webViewPlugin loadURL:url]; +} + +void _CWebViewPlugin_LoadHTML(void *instance, const char *html, const char *baseUrl) +{ + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)instance; + [webViewPlugin loadHTML:html baseURL:baseUrl]; +} + +void _CWebViewPlugin_EvaluateJS(void *instance, const char *js) +{ + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)instance; + [webViewPlugin evaluateJS:js]; +} + +BOOL _CWebViewPlugin_CanGoBack(void *instance) +{ + CWebViewPlugin *webViewPlugin = (__bridge CWebViewPlugin *)instance; + return [webViewPlugin canGoBack]; +} + +BOOL _CWebViewPlugin_CanGoForward(void *instance) +{ + CWebViewPlugin *webViewPlugin = (__bridge CWebViewPlugin *)instance; + return [webViewPlugin canGoForward]; +} + +void _CWebViewPlugin_GoBack(void *instance) +{ + CWebViewPlugin *webViewPlugin = (__bridge CWebViewPlugin *)instance; + [webViewPlugin goBack]; +} + +void _CWebViewPlugin_GoForward(void *instance) +{ + CWebViewPlugin *webViewPlugin = (__bridge CWebViewPlugin *)instance; + [webViewPlugin goForward]; +} + +void _CWebViewPlugin_Update(void *instance, int x, int y, float deltaY, + BOOL buttonDown, BOOL buttonPress, BOOL buttonRelease, BOOL keyPress, + unsigned char keyCode, const char *keyChars) +{ + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)instance; + [webViewPlugin update:x y:y deltaY:deltaY buttonDown:buttonDown + buttonPress:buttonPress buttonRelease:buttonRelease keyPress:keyPress + keyCode:keyCode keyChars:keyChars]; +} + +int _CWebViewPlugin_BitmapWidth(void *instance) +{ + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)instance; + return [webViewPlugin bitmapWide]; +} + +int _CWebViewPlugin_BitmapHeight(void *instance) +{ + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)instance; + return [webViewPlugin bitmapHigh]; +} + +void _CWebViewPlugin_SetTextureId(void *instance, int textureId) +{ + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)instance; + [webViewPlugin setTextureId:textureId]; +} + +static void *_instance; + +void _CWebViewPlugin_SetCurrentInstance(void *instance) +{ + _instance = instance; +} + +void UnityRenderEvent(int eventId) +{ + @autoreleasepool { + if (_instance == nil) { + return; + } + if ([pool containsObject:[NSValue valueWithPointer:(void *)_instance]]) { + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)_instance; + _instance = nil; + [webViewPlugin render]; + } + } +} + +UnityRenderEventFunc GetRenderEventFunc() +{ + return UnityRenderEvent; +} + +void _CWebViewPlugin_AddCustomHeader(void *instance, const char *headerKey, const char *headerValue) +{ + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)instance; + [webViewPlugin addCustomRequestHeader:headerKey value:headerValue]; +} + +void _CWebViewPlugin_RemoveCustomHeader(void *instance, const char *headerKey) +{ + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)instance; + [webViewPlugin removeCustomRequestHeader:headerKey]; +} + +const char *_CWebViewPlugin_GetCustomHeaderValue(void *instance, const char *headerKey) +{ + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)instance; + return [webViewPlugin getCustomRequestHeaderValue:headerKey]; +} + +void _CWebViewPlugin_ClearCustomHeader(void *instance) +{ + CWebViewPlugin *webViewPlugin = (CWebViewPlugin *)instance; + [webViewPlugin clearCustomRequestHeader]; +} + + diff --git a/plugins/Mac/WebView.xcodeproj/project.pbxproj b/plugins/Mac/WebView.xcodeproj/project.pbxproj index ac55345f..23a5f229 100644 --- a/plugins/Mac/WebView.xcodeproj/project.pbxproj +++ b/plugins/Mac/WebView.xcodeproj/project.pbxproj @@ -3,10 +3,16 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 48; objects = { /* Begin PBXBuildFile section */ + 183C36501EA488E50071D97B /* WebViewSeparated.m in Sources */ = {isa = PBXBuildFile; fileRef = 183C364F1EA488E50071D97B /* WebViewSeparated.m */; }; + 18E975FA1EA4873F00083D49 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 81B8C53715108B89000C56DC /* Carbon.framework */; }; + 18E975FB1EA4873F00083D49 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 81B8C534151078DB000C56DC /* WebKit.framework */; }; + 18E975FC1EA4873F00083D49 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 81F81AEC14D76D2400845D4C /* OpenGL.framework */; }; + 18E975FD1EA4873F00083D49 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 81E2C20B14C5684A004CE5C2 /* Cocoa.framework */; }; + 18E975FF1EA4873F00083D49 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8102525514C569D80022296D /* InfoPlist.strings */; }; 8102525814C569D80022296D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8102525514C569D80022296D /* InfoPlist.strings */; }; 81B8C535151078DB000C56DC /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 81B8C534151078DB000C56DC /* WebKit.framework */; }; 81B8C53815108B89000C56DC /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 81B8C53715108B89000C56DC /* Carbon.framework */; }; @@ -16,6 +22,9 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 183C364F1EA488E50071D97B /* WebViewSeparated.m */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; fileEncoding = 4; name = WebViewSeparated.m; path = Sources/WebViewSeparated.m; sourceTree = ""; }; + 18E976041EA4873F00083D49 /* WebViewSeparated.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WebViewSeparated.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 18E976051EA4873F00083D49 /* Info-WebViewSeparated.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = "Info-WebViewSeparated.plist"; path = "Resources/Info-WebViewSeparated.plist"; sourceTree = ""; }; 8102525414C569D80022296D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Resources/Info.plist; sourceTree = SOURCE_ROOT; }; 8102525514C569D80022296D /* InfoPlist.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = InfoPlist.strings; path = Resources/InfoPlist.strings; sourceTree = SOURCE_ROOT; }; 8102525614C569D80022296D /* Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Prefix.pch; path = Resources/Prefix.pch; sourceTree = SOURCE_ROOT; }; @@ -30,6 +39,17 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 18E975F91EA4873F00083D49 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 18E975FA1EA4873F00083D49 /* Carbon.framework in Frameworks */, + 18E975FB1EA4873F00083D49 /* WebKit.framework in Frameworks */, + 18E975FC1EA4873F00083D49 /* OpenGL.framework in Frameworks */, + 18E975FD1EA4873F00083D49 /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 81E2C20514C5684A004CE5C2 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -48,6 +68,7 @@ isa = PBXGroup; children = ( 81F4B4D814C6888B001B4465 /* WebView.m */, + 183C364F1EA488E50071D97B /* WebViewSeparated.m */, ); name = Sources; sourceTree = ""; @@ -66,6 +87,7 @@ isa = PBXGroup; children = ( 81E2C20814C5684A004CE5C2 /* WebView.bundle */, + 18E976041EA4873F00083D49 /* WebViewSeparated.bundle */, ); name = Products; sourceTree = ""; @@ -87,6 +109,7 @@ isa = PBXGroup; children = ( 8102525414C569D80022296D /* Info.plist */, + 18E976051EA4873F00083D49 /* Info-WebViewSeparated.plist */, 8102525514C569D80022296D /* InfoPlist.strings */, 8102525614C569D80022296D /* Prefix.pch */, ); @@ -97,6 +120,24 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 18E975F61EA4873F00083D49 /* WebViewSeparated */ = { + isa = PBXNativeTarget; + buildConfigurationList = 18E976011EA4873F00083D49 /* Build configuration list for PBXNativeTarget "WebViewSeparated" */; + buildPhases = ( + 18E975F71EA4873F00083D49 /* Sources */, + 18E975F91EA4873F00083D49 /* Frameworks */, + 18E975FE1EA4873F00083D49 /* Resources */, + 18E976001EA4873F00083D49 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = WebViewSeparated; + productName = WebView; + productReference = 18E976041EA4873F00083D49 /* WebViewSeparated.bundle */; + productType = "com.apple.product-type.bundle"; + }; 81E2C20714C5684A004CE5C2 /* WebView */ = { isa = PBXNativeTarget; buildConfigurationList = 81E2C21A14C5684A004CE5C2 /* Build configuration list for PBXNativeTarget "WebView" */; @@ -121,14 +162,15 @@ 81E2C1FF14C5684A004CE5C2 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0420; + LastUpgradeCheck = 0820; }; buildConfigurationList = 81E2C20214C5684A004CE5C2 /* Build configuration list for PBXProject "WebView" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 8.0"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 81E2C1FD14C5684A004CE5C2; productRefGroup = 81E2C20914C5684A004CE5C2 /* Products */; @@ -136,11 +178,20 @@ projectRoot = ""; targets = ( 81E2C20714C5684A004CE5C2 /* WebView */, + 18E975F61EA4873F00083D49 /* WebViewSeparated */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 18E975FE1EA4873F00083D49 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 18E975FF1EA4873F00083D49 /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 81E2C20614C5684A004CE5C2 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -152,6 +203,19 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 18E976001EA4873F00083D49 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = ""; + }; 81F4B4F514C696C4001B4465 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -168,6 +232,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 18E975F71EA4873F00083D49 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 183C36501EA488E50071D97B /* WebViewSeparated.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 81E2C20414C5684A004CE5C2 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -179,15 +251,62 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ + 18E976021EA4873F00083D49 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LIBRARY = "compiler-default"; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Resources/Prefix.pch; + INFOPLIST_FILE = "Resources/Info-WebViewSeparated.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; + LD_RUNPATH_SEARCH_PATHS = ""; + LIBRARY_SEARCH_PATHS = "$(inherited)"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + PRODUCT_BUNDLE_IDENTIFIER = "net.gree.unitywebview.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + VALID_ARCHS = x86_64; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 18E976031EA4873F00083D49 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LIBRARY = "compiler-default"; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Resources/Prefix.pch; + INFOPLIST_FILE = "Resources/Info-WebViewSeparated.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; + LD_RUNPATH_SEARCH_PATHS = ""; + LIBRARY_SEARCH_PATHS = "$(inherited)"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + PRODUCT_BUNDLE_IDENTIFIER = "net.gree.unitywebview.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + VALID_ARCHS = x86_64; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; 81E2C21814C5684A004CE5C2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -198,6 +317,9 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ""; MACOSX_DEPLOYMENT_TARGET = 10.6; @@ -214,15 +336,28 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ""; MACOSX_DEPLOYMENT_TARGET = 10.6; @@ -238,12 +373,14 @@ isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CLANG_CXX_LIBRARY = "compiler-default"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = Resources/Prefix.pch; INFOPLIST_FILE = Resources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; LD_RUNPATH_SEARCH_PATHS = ""; LIBRARY_SEARCH_PATHS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = "net.gree.unitywebview.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = bundle; }; @@ -253,12 +390,14 @@ isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CLANG_CXX_LIBRARY = "compiler-default"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = Resources/Prefix.pch; INFOPLIST_FILE = Resources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; LD_RUNPATH_SEARCH_PATHS = ""; LIBRARY_SEARCH_PATHS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = "net.gree.unitywebview.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = bundle; }; @@ -267,6 +406,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 18E976011EA4873F00083D49 /* Build configuration list for PBXNativeTarget "WebViewSeparated" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 18E976021EA4873F00083D49 /* Debug */, + 18E976031EA4873F00083D49 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 81E2C20214C5684A004CE5C2 /* Build configuration list for PBXProject "WebView" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/plugins/Mac/WebView.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/plugins/Mac/WebView.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index e970017a..00000000 --- a/plugins/Mac/WebView.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/plugins/Mac/WebView.xcodeproj/xcshareddata/xcschemes/WebView.xcscheme b/plugins/Mac/WebView.xcodeproj/xcshareddata/xcschemes/WebView.xcscheme deleted file mode 100644 index 0f50d2d9..00000000 --- a/plugins/Mac/WebView.xcodeproj/xcshareddata/xcschemes/WebView.xcscheme +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/plugins/Mac/WebViewSeparated.bundle.meta b/plugins/Mac/WebViewSeparated.bundle.meta new file mode 100644 index 00000000..c96417d4 --- /dev/null +++ b/plugins/Mac/WebViewSeparated.bundle.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 5ad99e2446f6f450185b777a22f98f2a +folderAsset: yes +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Android: + enabled: 0 + settings: + CPU: AnyCPU + Any: + enabled: 0 + settings: {} + Editor: + enabled: 1 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: OSX + Linux: + enabled: 0 + settings: + CPU: x86 + Linux64: + enabled: 0 + settings: + CPU: x86_64 + OSXIntel: + enabled: 0 + settings: + CPU: AnyCPU + OSXIntel64: + enabled: 1 + settings: + CPU: x86_64 + OSXUniversal: + enabled: 0 + settings: {} + Win: + enabled: 0 + settings: + CPU: AnyCPU + Win64: + enabled: 0 + settings: + CPU: AnyCPU + iOS: + enabled: 0 + settings: + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/plugins/Mac/install.sh b/plugins/Mac/install.sh index 0e2a2f66..cc1160ba 100755 --- a/plugins/Mac/install.sh +++ b/plugins/Mac/install.sh @@ -1,8 +1,10 @@ #!/bin/sh DSTDIR="../../build/Packager/Assets/Plugins" rm -rf DerivedData -xcodebuild -scheme WebView -configuration Release -arch i386 -arch x86_64 build CONFIGURATION_BUILD_DIR='DerivedData' +xcodebuild -target WebView -configuration Release -arch i386 -arch x86_64 build CONFIGURATION_BUILD_DIR='DerivedData' +xcodebuild -target WebViewSeparated -configuration Release -arch x86_64 build CONFIGURATION_BUILD_DIR='DerivedData' mkdir -p $DSTDIR cp -r DerivedData/WebView.bundle $DSTDIR +cp -r DerivedData/WebViewSeparated.bundle $DSTDIR rm -rf DerivedData -cp WebView.bundle.meta $DSTDIR +cp *.bundle.meta $DSTDIR diff --git a/plugins/WebViewObject.cs b/plugins/WebViewObject.cs index 0dbe327f..dadc042a 100644 --- a/plugins/WebViewObject.cs +++ b/plugins/WebViewObject.cs @@ -86,6 +86,64 @@ public bool IsKeyboardVisible } #if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX +#if WEBVIEW_SEPARATED + [DllImport("WebViewSeparated")] + private static extern string _CWebViewPlugin_GetAppPath(); + [DllImport("WebViewSeparated")] + private static extern IntPtr _CWebViewPlugin_Init( + string gameObject, bool transparent, int width, int height, string ua, bool ineditor); + [DllImport("WebViewSeparated")] + private static extern int _CWebViewPlugin_Destroy(IntPtr instance); + [DllImport("WebViewSeparated")] + private static extern void _CWebViewPlugin_SetRect( + IntPtr instance, int width, int height); + [DllImport("WebViewSeparated")] + private static extern void _CWebViewPlugin_SetVisibility( + IntPtr instance, bool visibility); + [DllImport("WebViewSeparated")] + private static extern void _CWebViewPlugin_LoadURL( + IntPtr instance, string url); + [DllImport("WebViewSeparated")] + private static extern void _CWebViewPlugin_LoadHTML( + IntPtr instance, string html, string baseUrl); + [DllImport("WebViewSeparated")] + private static extern void _CWebViewPlugin_EvaluateJS( + IntPtr instance, string url); + [DllImport("WebViewSeparated")] + private static extern bool _CWebViewPlugin_CanGoBack( + IntPtr instance); + [DllImport("WebViewSeparated")] + private static extern bool _CWebViewPlugin_CanGoForward( + IntPtr instance); + [DllImport("WebViewSeparated")] + private static extern void _CWebViewPlugin_GoBack( + IntPtr instance); + [DllImport("WebViewSeparated")] + private static extern void _CWebViewPlugin_GoForward( + IntPtr instance); + [DllImport("WebViewSeparated")] + private static extern void _CWebViewPlugin_Update(IntPtr instance, + int x, int y, float deltaY, bool down, bool press, bool release, + bool keyPress, short keyCode, string keyChars); + [DllImport("WebViewSeparated")] + private static extern int _CWebViewPlugin_BitmapWidth(IntPtr instance); + [DllImport("WebViewSeparated")] + private static extern int _CWebViewPlugin_BitmapHeight(IntPtr instance); + [DllImport("WebViewSeparated")] + private static extern void _CWebViewPlugin_SetTextureId(IntPtr instance, int textureId); + [DllImport("WebViewSeparated")] + private static extern void _CWebViewPlugin_SetCurrentInstance(IntPtr instance); + [DllImport("WebViewSeparated")] + private static extern IntPtr GetRenderEventFunc(); + [DllImport("WebViewSeparated")] + private static extern void _CWebViewPlugin_AddCustomHeader(IntPtr instance, string headerKey, string headerValue); + [DllImport("WebViewSeparated")] + private static extern string _CWebViewPlugin_GetCustomHeaderValue(IntPtr instance, string headerKey); + [DllImport("WebViewSeparated")] + private static extern void _CWebViewPlugin_RemoveCustomHeader(IntPtr instance, string headerKey); + [DllImport("WebViewSeparated")] + private static extern void _CWebViewPlugin_ClearCustomHeader(IntPtr instance); +#else [DllImport("WebView")] private static extern string _CWebViewPlugin_GetAppPath(); [DllImport("WebView")] @@ -142,7 +200,7 @@ private static extern void _CWebViewPlugin_Update(IntPtr instance, private static extern void _CWebViewPlugin_RemoveCustomHeader(IntPtr instance, string headerKey); [DllImport("WebView")] private static extern void _CWebViewPlugin_ClearCustomHeader(IntPtr instance); - +#endif #elif UNITY_IPHONE [DllImport("__Internal")] private static extern IntPtr _CWebViewPlugin_Init(string gameObject, bool transparent, bool enableWKWebView); diff --git a/plugins/iOS/WebView.mm b/plugins/iOS/WebView.mm index a2640905..310621f2 100644 --- a/plugins/iOS/WebView.mm +++ b/plugins/iOS/WebView.mm @@ -117,7 +117,7 @@ - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void @end -@interface CWebViewPlugin : NSObject +@interface CWebViewPlugin : NSObject { UIView *webView; NSString *gameObjectName; @@ -135,7 +135,11 @@ - (id)initWithGameObjectName:(const char *)gameObjectName_ transparent:(BOOL)tra UIView *view = UnityGetGLViewController().view; if (enableWKWebView && [WKWebView class]) { - webView = [[WKWebView alloc] initWithFrame:view.frame]; + WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; + WKUserContentController *controller = [[WKUserContentController alloc] init]; + [controller addScriptMessageHandler:self name:@"unityControl"]; + configuration.userContentController = controller; + webView = [[WKWebView alloc] initWithFrame:view.frame configuration:configuration]; webView.UIDelegate = self; webView.navigationDelegate = self; } else { @@ -176,6 +180,25 @@ - (void)dealloc customRequestHeader = nil; } +- (void)userContentController:(WKUserContentController *)userContentController + didReceiveScriptMessage:(WKScriptMessage *)message { + + // Log out the message received + NSLog(@"Received event %@", message.body); + UnitySendMessage([gameObjectName UTF8String], "CallFromJS", + [[NSString stringWithFormat:@"%@", message.body] UTF8String]); + + /* + // Then pull something from the device using the message body + NSString *version = [[UIDevice currentDevice] valueForKey:message.body]; + + // Execute some JavaScript using the result? + NSString *exec_template = @"set_headline(\"received: %@\");"; + NSString *exec = [NSString stringWithFormat:exec_template, version]; + [webView evaluateJavaScript:exec completionHandler:nil]; + */ +} + - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change