Simple Swift WebView not working (Xcode 6 Beta 3) - uiwebview

I was writing a simple WebView in Swift, but everytime I try to launch it in the iOS Simulator I get these errors. What is going wrong?
import UIKit
class ViewController: UIViewController {
#IBOutlet var webview: UIWebView
var urlpath = "http://www.google.de"
func loadAddressURL(){
let requesturl = NSURL(string: urlpath)
let request = NSURLRequest(URL: requesturl)
webview.loadRequest(request)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
loadAddressURL()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Error:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
self uiwebview.ViewController 0x7987fc70 0x7987fc70
request NSURLRequest * 0x78ebfc40 0x78ebfc40
requesturl NSURL * "" 0x78ec0040

You simply haven't connected your UIWebView to the webview class property
Open the assistant editor, show your xib or storyboard at left, your view controller source file at right, click on the circle at the left of the webview property and drag into the UIWebView control. Once the connection is established, run the app and it should work now

I guess you get a white page because you test on the simulator. If you test on a real device you should be fine.

You need to put "!" after 'UIWebView' and unwrap "requesturl" to get your String value otherwise it's been an optional and you get error.
import UIKit
class WebViewController: UIViewController {
#IBOutlet var webview: UIWebView!
var urlpath: String = "http://www.google.de"
func loadAddressURL(){
let requesturl = NSURL(string: urlpath)
let request = NSURLRequest(URL: requesturl!)
webview.loadRequest(request)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
loadAddressURL()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Related

Displaying input text on different views

Was wondering if anybody could help on a simple problem
I have a UITextView on one page, where I want to enter text and store it in a string. Then when the next page is accessed, I would like that text to be displayed on that page, either in a new UITextView or some other way.
In my PostViewController.swift file (the first page) to get the input string, I have
#IBOutlet weak var postTextView: UITextView!
I tried making a new UITextView on the other view controller to try and display the string, and had the subsequent code, but can't figure it out from here.
#IBOutlet weak var copyText: UITextView!
let text: NSString = PostViewController().postTextView.text
???copyText = text??? (not sure if this is even close to right)
Any ideas would be appreciated and apologies for the noob question
In your PostViewController, implement prepareForSegue() to assign the value of its textfield to the variable in the second controller.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showSecondVC" { // Make sure the segue has this identity in Interface Builder
let vc = segue.destinationViewController as! SecondVC // Change that to the actual class name
vc.textFromVC1 = postTextView.text
}
}
In your second ViewController:
class SecondviewController: UIViewController {
var textFromVC1: String!
#IBOutlet weak var myTextField: UITextField!
override func viewDidLoad() {
myTextField.text = textFromVC1
}
}

iOS 9 issues - GameCenter

Since iOS 9 errors are appearing in the console when opening the Game Center View Controller. I have created a bare bones sample project to help diagnose and isolate the issue. My bare bones View Controller contains a UIButton to open the Game Center, and my code is the following:
import UIKit
import GameKit
class ViewController: UIViewController, GKGameCenterControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let localPlayer = GKLocalPlayer()
localPlayer.authenticateHandler = {(viewController, error) -> Void in
if let viewController = viewController {
self.presentViewController(viewController, animated: true, completion: nil)
}else{
print("(GameCenter) Player authenticated: \(GKLocalPlayer.localPlayer().authenticated)")
}
}
}
#IBAction func openGameCenter(sender: AnyObject) {
let gameCenter = GKGameCenterViewController()
gameCenter.gameCenterDelegate = self
self.presentViewController(gameCenter, animated: true, completion: nil)
}
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController) {
gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}
}
When presenting the Game Center View Controller, I see the following errors in the console:
2015-09-21 11:03:41.530 GameCenterTest[1552:415921] - changing property masksToBounds in transform-only
layer, will have no effect 2015-09-21 11:03:41.531
GameCenterTest[1552:415921] - changing
property masksToBounds in transform-only layer, will have no effect
2015-09-21 11:03:41.532 GameCenterTest[1552:415921] - changing property masksToBounds in transform-only
layer, will have no effect
When tapping on Done and closing the Game Center View Cotroller, I see the following error in the console:
2015-09-21 11:03:52.263 GameCenterTest[1552:416142] plugin
com.apple.GameCenterUI.GameCenterDashboardExtension invalidated

How to Migrate to WKWebView?

I'm trying to understand how to make use of the new WKWebView in iOS8, can't find much information. I've read:
http://developer.telerik.com/featured/why-ios-8s-wkwebview-is-a-big-deal-for-hybrid-development/
http://nshipster.com/wkwebkit/
But how does this affect existing apps? Will an ordinary UiWebView get the speedup from the nitro java script engine or do we need to make changes? How do we deal with backwards compatibility?
All the code and examples I can find are using swift, will this be mandatory?
Thankful for any help on this matter!
UIWebView will still continue to work with existing apps. WKWebView is available starting from iOS8, only WKWebView has a Nitro JavaScript engine.
To take advantage of this faster JavaScript engine in older apps you have to make code changes to use WKWebView instead of UIWebView. For iOS7 and older, you have to continue to use UIWebView, so you may have to check for iOS8 and then apply WKWebView methods / delegate methods and fallback to UIWebView methods for iOS7 and older. Also there is no Interface Builder component for WKWebView (yet), so you have to programmatically implement WKWebView.
You can implement WKWebView in Objective-C, here is simple example to initiate a WKWebView:
WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:theConfiguration];
webView.navigationDelegate = self;
NSURL *nsurl=[NSURL URLWithString:#"http://www.apple.com"];
NSURLRequest *nsrequest=[NSURLRequest requestWithURL:nsurl];
[webView loadRequest:nsrequest];
[self.view addSubview:webView];
WKWebView rendering performance is noticeable in WebGL games and something that runs complex JavaScript algorithms, if you are using webview to load a simple html or website, you can continue to use UIWebView.
Here is a test app that can used to open any website using either UIWebView or WKWebView and you can compare performance, and then decide on upgrading your app to use WKWebView:
https://itunes.apple.com/app/id928647773?mt=8&at=10ltWQ
Here is how I transitioned from UIWebView to WKWebView.
Note: There is no property like UIWebView that you can drag onto your
storyboard, you have to do it programatically.
Make sure you import WebKit/WebKit.h into your header file.
This is my header file:
#import <WebKit/WebKit.h>
#interface ViewController : UIViewController
#property(strong,nonatomic) WKWebView *webView;
#property (strong, nonatomic) NSString *productURL;
#end
Here is my implementation file:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.productURL = #"http://www.URL YOU WANT TO VIEW GOES HERE";
NSURL *url = [NSURL URLWithString:self.productURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
_webView = [[WKWebView alloc] initWithFrame:self.view.frame];
[_webView loadRequest:request];
_webView.frame = CGRectMake(self.view.frame.origin.x,self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height);
[self.view addSubview:_webView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Step : 1 Import webkit in ViewController.swift
import WebKit
Step : 2 Declare variable of webView.
var webView : WKWebView!
Step : 3 Adding Delegate of WKNavigationDelegate
class ViewController: UIViewController , WKNavigationDelegate{
Step : 4 Adding code in ViewDidLoad.
let myBlog = "https://iosdevcenters.blogspot.com/"
let url = NSURL(string: myBlog)
let request = NSURLRequest(URL: url!)
// init and load request in webview.
webView = WKWebView(frame: self.view.frame)
webView.navigationDelegate = self
webView.loadRequest(request)
self.view.addSubview(webView)
self.view.sendSubviewToBack(webView)
Step : 5 Edit the info.plist adding
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>google.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
Swift is not a requirement, everything works fine with Objective-C. UIWebView will continue to be supported, so there is no rush to migrate if you want to take your time. However, it will not get the javascript and scrolling performance enhancements of WKWebView.
For backwards compatibility, I have two properties for my view controller: a UIWebView and a WKWebView. I use the WKWebview only if the class exists:
if ([WKWebView class]) {
// do new webview stuff
} else {
// do old webview stuff
}
Whereas I used to have a UIWebViewDelegate, I also made it a WKNavigationDelegate and created the necessary methods.
WkWebView is much faster and reliable than UIWebview according to the Apple docs.
Here, I posted my WkWebViewController.
import UIKit
import WebKit
class WebPageViewController: UIViewController,UINavigationControllerDelegate,UINavigationBarDelegate,WKNavigationDelegate{
var webView: WKWebView?
var webUrl="http://www.nike.com"
override func viewWillAppear(animated: Bool){
super.viewWillAppear(true)
navigationController!.navigationBar.hidden = false
}
override func viewDidLoad()
{
/* Create our preferences on how the web page should be loaded */
let preferences = WKPreferences()
preferences.javaScriptEnabled = false
/* Create a configuration for our preferences */
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
/* Now instantiate the web view */
webView = WKWebView(frame: view.bounds, configuration: configuration)
if let theWebView = webView{
/* Load a web page into our web view */
let url = NSURL(string: self.webUrl)
let urlRequest = NSURLRequest(URL: url!)
theWebView.loadRequest(urlRequest)
theWebView.navigationDelegate = self
view.addSubview(theWebView)
}
}
/* Start the network activity indicator when the web view is loading */
func webView(webView: WKWebView,didStartProvisionalNavigation navigation: WKNavigation){
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
}
/* Stop the network activity indicator when the loading finishes */
func webView(webView: WKWebView,didFinishNavigation navigation: WKNavigation){
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}
func webView(webView: WKWebView,
decidePolicyForNavigationResponse navigationResponse: WKNavigationResponse,decisionHandler: ((WKNavigationResponsePolicy) -> Void)){
//print(navigationResponse.response.MIMEType)
decisionHandler(.Allow)
}
override func didReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
}
}
WKWebView using Swift in iOS 8..
The whole ViewController.swift file now looks like this:
import UIKit
import WebKit
class ViewController: UIViewController {
#IBOutlet var containerView : UIView! = nil
var webView: WKWebView?
override func loadView() {
super.loadView()
self.webView = WKWebView()
self.view = self.webView!
}
override func viewDidLoad() {
super.viewDidLoad()
var url = NSURL(string:"http://www.kinderas.com/")
var req = NSURLRequest(URL:url)
self.webView!.loadRequest(req)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Use some design patterns, you can mix UIWebView and WKWebView.
The key point is to design a unique browser interface.
But you should pay more attention to your app's current functionality,
for example: if your app using NSURLProtocol to enhance network ability, using WKWebView you have no chance to do the same thing. Because NSURLProtocol only effects the current process, and WKWebView using muliti-process architecture, the networking staff is in a seperate process.
You have to use WKWebView, which is available as of iOS8 in Framework 'WebKit' to get the speedup.
If you need backwards compatibility, you have to use UIWebView for iOS7 and older.
I set up a little code to provide the UIViewController frame for the new WKWebView. It can be installed via cocoapods. Have a look here:
STKWebKitViewController on github
Swift 4
let webView = WKWebView() // Set Frame as per requirment, I am leaving it for you
let url = URL(string: "http://www.google.com")!
webView.load(URLRequest(url: url))
view.addSubview(webView)

Hiding the Navigation Bar in Xamarin Project using Mvvmcross

I'm using mvvmcross and implementing the view's interface in code behind. I would like to hide the navigation bar but I have not found a solution yet.
I tried
NavigationController.SetNavigationBarHidden(true, false);
and
NavigationController.NavigationBarHidden = true;
in different methods (ViewDidAppear and ViewWillAppear) but they don't have an impact on the UI.
Maybe someone could give me a hint. :-)
#Edit: Some more information:
My AppDelegate.cs
[Register("AppDelegate")]
public partial class AppDelegate : MvxApplicationDelegate
{
UIWindow _window;
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
_window = new UIWindow(UIScreen.MainScreen.Bounds);
var setup = new Setup(this, _window);
setup.Initialize();
var startup = Mvx.Resolve<IMvxAppStart>();
startup.Start();
_window.MakeKeyAndVisible();
return true;
}
}
Additionally I'm using a BaseView class which inherits from MvxViewController.
Okay, found the solution by myself:
Just paste the following code into the ViewDidLoad method in your MvxViewController class( for example FirstView.cs in many mvvmcross tutorials):
var navController = base.NavigationController;
navController.NavigationBarHidden = true;
I know it is a +6 years old question but came across finding a solution for this using MVVMCross and found out that using this into the xaml of your view should be enough: <NavigationPage.HasNavigationBar>False</NavigationPage.HasNavigationBar>
It should apply for both Xamarin Android and iOS.
This will kill it, let me know if you have questions.
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
// class-level declarations
UIWindow window;
MyViewController viewController;
MainViewController mainViewController;
UINavigationController navController;
public UINavigationController NavController { get { return navController; }}
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
var navController = new UINavigationController();
navController.SetNavigationBarHidden (true, false);
window = new UIWindow (UIScreen.MainScreen.Bounds);
viewController = new MyViewController();
app.SetStatusBarStyle (UIStatusBarStyle.LightContent, true);
navController.PushViewController(viewController, false);
window.RootViewController = navController;
window.MakeKeyAndVisible ();
return true;
}
}
}
The default presenter uses a UINavigationController for the RootController on the window; so you can manipulate the navigation bar globally in the AppDelegate by grabbing it off the window and casting:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
window = new UIWindow(UIScreen.MainScreen.Bounds);
new Setup(this, window).Initialize();
Mvx.Resolve<IMvxAppStart>().Start();
var navigationBar = ((UINavigationController)window.RootViewController).NavigationBar;
navigationBar.BackgroundColor = UIColor.Black;
navigationBar.BarTintColor = UIColor.Black;
navigationBar.TintColor = UIColor.White;
window.MakeKeyAndVisible();
return true;
}

Issue with Game Center on Monotouch

I'm trying to implement Game Center into my game but i have problems with it.
Here is my Main.cs code :
namespace iosgame
{
public class Application
{
[Register ("AppDelegate")]
public partial class AppDelegate : IOSApplication {
MainViewController mainViewController;
public AppDelegate(): base(new Game(new StaticsDatabase(),new StoreDatabase(),new InappPurchase(),new Social(),new MissionsDatabase()), getConfig()) {
}
internal static IOSApplicationConfiguration getConfig() {
IOSApplicationConfiguration config = new IOSApplicationConfiguration();
config.orientationLandscape = true;
config.orientationPortrait = false;
config.useAccelerometer = false;
config.useMonotouchOpenTK = true;
config.useObjectAL = true;
return config;
}
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
base.FinishedLaunching(app,options);
UIViewController controller = ((IOSApplication)Gdx.app).getUIViewController();
mainViewController = new MainViewController();
controller.View.Add(mainViewController.View);
return true;
}
private bool isGameCenterAPIAvailable()
{
return UIDevice.CurrentDevice.CheckSystemVersion (4, 1);
}
}
static void Main (string[] args)
{
UIApplication.Main (args, null, "AppDelegate");
}
}
}
And here is the superclass of that Main.cs : https://github.com/libgdx/libgdx/blob/master/backends/gdx-backend-iosmonotouch/src/com/badlogic/gdx/backends/ios/IOSApplication.java
I'm trying to use this https://github.com/xamarin/monotouch-samples/blob/master/GameCenterSample/GameCenterSample/MainViewController.cs example but i can't see any authenticate window in my game.I can see "Welcome back ,name" notification but after i log out from gamecenter app and reopen my game but i can't see any authentication window.
How can i fix it?
Thanks in advance
Just call this in FinishedLaunching:
if (!GKLocalPlayer.LocalPlayer.Authenticated) {
GKLocalPlayer.LocalPlayer.Authenticate (error => {
if (error != null)
Console.WriteLine("Error: " + error.LocalizedDescription);
});
}
This should display a Game Center "toast" saying "Welcome back, Player 1".
Here are some ideas if this doesn't work:
Make sure you have setup a new bundle id in the developer portal, and declare it in your Info.plist
Start filling out your app details in iTunes connect (Minimum is description, keywords, icon, 1 screenshot), and make sure to enable Game Center and add your new game to a group
Login with a test iTunes user in Game Center (create in ITC), or the login associated with your developer account
PS - I wouldn't worry about checking for iOS 4.1, just target iOS 5.0 and higher these days.

Resources