Sharing photo with Whatsapp not working under Xcode 9.1 and iOS11 - swift3

The below code used to work in Xcode8. But now it is not working in Xcode 9.1 with target iOS11.
I did the following:
class ViewController: UIViewController {
var documentInteractionController: UIDocumentInteractionController = UIDocumentInteractionController()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func ShareImages(_ sender: AnyObject)
{
let urlWhats = "whatsapp://app"
if let urlString = urlWhats.addingPercentEncoding(withAllowedCharacters:CharacterSet.urlQueryAllowed) {
if let whatsappURL = URL(string: urlString) {
if UIApplication.shared.canOpenURL(whatsappURL as URL) {
if let image = UIImage(named: "whatsappIcon") {
if let imageData = UIImageJPEGRepresentation(image, 1.0) {
let tempFile = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("Documents/whatsAppTmp.wai")
do {
try imageData.write(to: tempFile, options: .atomic)
self.documentInteractionController = UIDocumentInteractionController(url: tempFile)
self.documentInteractionController.uti = "net.whatsapp.image"
self.documentInteractionController.presentOpenInMenu(from: CGRect.zero, in: self.view, animated: true)
} catch {
print(error)
}
}
}
} else {
// Cannot open whatsapp
}
}
}
}
// Added this in info.plist
<key>LSApplicationQueriesSchemes</key>
<array>
<string>whatsapp</string>
</array>

Related

SwiftUI: Highlighting Text with different colors using WkWebView

I am trying to use swiftUI to be able to create a custom EPUB reader. Ive looked around at some but none fit my needs. I want to be able to customize it. The issue I have ran into is being able to Highlight text while reading either Orange, blue, green, etc. When highlight a text and then the menu bar pops up and I click on my custom MenuBar color the app crashes. I found this article on highlighting text but uses the UIkit and not SwiftUI. Ive been trying to "translate"(not sure what the correct term is)it to use it with SwiftUI but crashes due to unrecognized selector.Im thinking I am not setting up the things correct. Not sure if it is worth using SwiftUI anymore and just switching my app to UIKit at this point since I have not been able to find many resources using swiftUI. Here is article to highlight text : https://dailong.medium.com/highlight-text-in-wkwebview-1659a19715e6
Just started learning swiftUI so not sure if the way the WebView is setup is correct.
Here is the gitHub link to all of the code https://github.com/longvudai/demo/tree/master/highlight-webview/highlight-webview With the SwiftUI all i did was copy and paste the files. Only difference is with SwiftUI was wrapping the WebView other than that everything else is the same.
SWIFTUI
`struct WebView: UIViewRepresentable {
class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
var webView: CustomView?
var serializedObject: SerializedObject?
private var dataStack = Stack<Highlights>()
func webView(_ webView: WKWebView?, didFinish navigation: WKNavigation!) {
self.webView = webView as? CustomView
}
// receive message from wkwebview
func userContentController(
_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage
) {
if let markerHandler = MarkerScript.Handler(message) {
guard
let dataString = message.body as? String,
let data = dataString.data(using: .utf8)
else { return }
let decoder = JSONDecoder()
guard let serialized = try? decoder.decode(
SerializedObject.self,
from: data
) else { return }
receiveMarkerMessage(markerHandler, data: serialized)
}
}
func receiveMarkerMessage(_ handler: MarkerScript.Handler, data: SerializedObject) {
switch handler {
case .serialize:
serializedObject = data
// your callback here
let script = MarkerScript.Evaluate.clearSelection()
self.webView?.evaluateJavaScript(script)
case .erase:
serializedObject = data
let highlights = data.highlights
let listId = highlights.map { $0.id }
guard let top = dataStack.top else { return }
let newData = top.filter { listId.contains($0.id) }
if newData != top {
dataStack.push(newData)
}
}
}
func highlight(_ color: MarkerColor) {
let script =
MarkerScript.Evaluate.highlightSelectedTextWithColor(color)
webView?.evaluateJavaScript(script)
print("highlightfunction")
}
func removeAll() {
let script = MarkerScript.Evaluate.removeAllHighlights()
self.webView?.evaluateJavaScript(script)
dataStack.push([])
}
func erase() {
let script = MarkerScript.Evaluate.erase()
self.webView?.evaluateJavaScript(script)
}
#objc func highlightthiscolor() {
highlight(MarkerColor.orange)
}
}
func makeCoordinator() -> Coordinator {
return Coordinator()
}
func makeUIView(context: Context) -> CustomView {
let coordinator = makeCoordinator()
let configuration = WKWebViewConfiguration()
let uc = configuration.userContentController
uc.addUserScript(WKUserScript.injectViewPort())
// Jquery
uc.addUserScript(JQueryScript.core())
// Rangy
uc.addUserScript(RangyScript.core())
uc.addUserScript(RangyScript.classapplier())
uc.addUserScript(RangyScript.highlighter())
uc.addUserScript(RangyScript.selectionsaverestore())
uc.addUserScript(RangyScript.textrange())
// Marker
uc.addUserScript(MarkerScript.css())
uc.addUserScript(MarkerScript.jsScript())
uc.add(coordinator, name: MarkerScript.Handler.serialize.rawValue)
uc.add(coordinator, name: MarkerScript.Handler.erase.rawValue)
let _wkwebview = CustomView(frame: .zero, configuration: configuration)
_wkwebview.navigationDelegate = coordinator
return _wkwebview
}
func updateUIView(_ webView: CustomView, context: Context) {
guard let path: String = Bundle.main.path(forResource: "sample", ofType: "html") else { return }
let localHTMLUrl = URL(fileURLWithPath: path, isDirectory: false)
webView.loadFileURL(localHTMLUrl, allowingReadAccessTo: localHTMLUrl)
addCustomContextMenu()
}
func addCustomContextMenu(){
//Has to be type of WKWebView
let colorOrange:UIMenuItem = UIMenuItem(title: "Orange", action: #selector(Coordinator.highlightthiscolor))
UIMenuController.shared.menuItems = [colorOrange]
}
}`
UIKit
protocol MarkerLogic {
func erase()
func highlight(_ color: MarkerColor)
func removeAll()
}
class Marker: NSObject {
weak var webView: WKWebView?
var serializedObject: SerializedObject?
private var dataStack = Stack<Highlights>()
}
extension Marker: MarkerLogic {
func highlight(_ color: MarkerColor) {
let script =
MarkerScript.Evaluate.highlightSelectedTextWithColor(color)
webView?.evaluateJavaScript(script)
}
func removeAll() {
let script = MarkerScript.Evaluate.removeAllHighlights()
webView?.evaluateJavaScript(script)
dataStack.push([])
}
func erase() {
let script = MarkerScript.Evaluate.erase()
webView?.evaluateJavaScript(script)
}
}
// MARK: - WKScriptMessageHandler
extension Marker: WKScriptMessageHandler {
func userContentController(
_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage
) {
if let markerHandler = MarkerScript.Handler(message) {
guard
let dataString = message.body as? String,
let data = dataString.data(using: .utf8)
else { return }
let decoder = JSONDecoder()
guard let serialized = try? decoder.decode(
SerializedObject.self,
from: data
) else { return }
receiveMarkerMessage(markerHandler, data: serialized)
}
}
func receiveMarkerMessage(_ handler: MarkerScript.Handler, data: SerializedObject) {
switch handler {
case .serialize:
serializedObject = data
// your callback here
let script = MarkerScript.Evaluate.clearSelection()
webView?.evaluateJavaScript(script)
case .erase:
serializedObject = data
let highlights = data.highlights
let listId = highlights.map { $0.id }
guard let top = dataStack.top else { return }
let newData = top.filter { listId.contains($0.id) }
if newData != top {
dataStack.push(newData)
}
}
}
}
--- ViewDidLoad
class ViewController: UIViewController, WKScriptMessageHandler {
let marker: Marker = Marker()
let orangeButton: UIButton = {
let v = UIButton()
v.tag = 0
v.backgroundColor = MarkerColor.orange.value
v.layer.cornerRadius = 10
v.addTarget(self, action: #selector(highlight(_:)), for: .touchUpInside)
return v
}()
let cyanButton: UIButton = {
let v = UIButton()
v.tag = 1
v.backgroundColor = MarkerColor.cyan.value
v.layer.cornerRadius = 10
v.addTarget(self, action: #selector(highlight(_:)), for: .touchUpInside)
return v
}()
let pinkButton: UIButton = {
let v = UIButton()
v.tag = 2
v.backgroundColor = MarkerColor.pink.value
v.layer.cornerRadius = 10
v.addTarget(self, action: #selector(highlight(_:)), for: .touchUpInside)
return v
}()
let eraseButton: UIButton = {
let v = UIButton()
v.setTitle("Erase", for: .normal)
v.setTitleColor(.systemBlue, for: .normal)
v.addTarget(self, action: #selector(erase), for: .touchUpInside)
return v
}()
let eraseAllButton: UIButton = {
let v = UIButton(type: .close)
v.addTarget(self, action: #selector(eraseAll), for: .touchUpInside)
return v
}()
lazy var toolBars: UIStackView = {
let v = UIStackView(arrangedSubviews: [orangeButton, cyanButton, pinkButton, eraseButton, eraseAllButton])
v.axis = .horizontal
v.distribution = .fillEqually
v.spacing = 20
return v
}()
// This is to make the makeUIView
lazy var webView: WKWebView = {
let config = WKWebViewConfiguration()
let uc = config.userContentController
uc.addUserScript(WKUserScript.injectViewPort())
// Jquery
uc.addUserScript(JQueryScript.core())
// Rangy
uc.addUserScript(RangyScript.core())
uc.addUserScript(RangyScript.classapplier())
uc.addUserScript(RangyScript.highlighter())
uc.addUserScript(RangyScript.selectionsaverestore())
uc.addUserScript(RangyScript.textrange())
// Marker
uc.addUserScript(MarkerScript.css())
uc.addUserScript(MarkerScript.jsScript())
uc.add(self.marker, name: MarkerScript.Handler.serialize.rawValue)
uc.add(self.marker, name: MarkerScript.Handler.erase.rawValue)
let v = WKWebView(frame: .zero, configuration: config)
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
marker.webView = webView
let path = Bundle.main.path(forResource: "sample", ofType: "html")!
let url = URL(fileURLWithPath: path)
webView.loadFileURL(url, allowingReadAccessTo: url)
let views = [webView, toolBars]
views.forEach {
view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
NSLayoutConstraint.activate([
webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40),
webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
webView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
toolBars.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
toolBars.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
toolBars.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
toolBars.heightAnchor.constraint(equalToConstant: 40)
])
}
// MARK: - Selector
#objc func highlight(_ sender: UIButton) {
switch sender.tag {
case 0:
marker.highlight(MarkerColor.orange)
case 1:
marker.highlight(MarkerColor.cyan)
case 2:
marker.highlight(MarkerColor.pink)
default:
break
}
}
#objc func erase() {
marker.erase()
}
#objc func eraseAll() {
marker.removeAll()
}
// MARK: - WKScriptMessageHandler
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
}
}
I was finally able to get the code working by looking at the post: Call evaluateJavascript from a SwiftUI button. The problem I was running into was the fact that I was not able to run the javascript func in order to highlight. Using Combine i was able to make a button in the View and when that button is clicked being able to run the javascript code. Will post the code below for anyone who is interested.
import WebKit
import SwiftUI
import Combine
class WebViewData: ObservableObject {
#Published var parsedText: NSAttributedString? = nil
var functionCaller = PassthroughSubject<Void,Never>()
var isInit = false
var shouldUpdateView = true
}
struct ContentView: View {
#StateObject var webViewData = WebViewData()
var body: some View {
VStack {
Button(action: {
webViewData.functionCaller.send()
}) {
Text("Orange")
}
WebView(data: webViewData)
}
}
}
struct WebView: UIViewRepresentable {
#StateObject var data: WebViewData
class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
//var webView: WKWebView?
var serializedObject: SerializedObject?
private var dataStack = Stack<Highlights>()
var parent: WebView
var webView: WKWebView? = nil
private var cancellable : AnyCancellable?
init(view: WebView) {
self.parent = view
super.init()
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.webView = webView
}
// receive message from wkwebview
func userContentController(
_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage
) {
if let markerHandler = MarkerScript.Handler(message) {
guard
let dataString = message.body as? String,
let data = dataString.data(using: .utf8)
else { return }
let decoder = JSONDecoder()
guard let serialized = try? decoder.decode(
SerializedObject.self,
from: data
) else { return }
receiveMarkerMessage(markerHandler, data: serialized)
}
}
func receiveMarkerMessage(_ handler: MarkerScript.Handler, data: SerializedObject) {
switch handler {
case .serialize:
serializedObject = data
// your callback here
let script = MarkerScript.Evaluate.clearSelection()
self.webView?.evaluateJavaScript(script)
case .erase:
serializedObject = data
let highlights = data.highlights
let listId = highlights.map { $0.id }
guard let top = dataStack.top else { return }
let newData = top.filter { listId.contains($0.id) }
if newData != top {
dataStack.push(newData)
}
}
}
func tieFunctionCaller(data: WebViewData) {
cancellable = data.functionCaller.sink(receiveValue: { _ in
self.webView?.evaluateJavaScript("highlightSelectedTextWithColor('orange')")
})
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(view: self)
}
func makeUIView(context: Context) -> WKWebView {
let coordinator = makeCoordinator()
let configuration = WKWebViewConfiguration()
let uc = configuration.userContentController
uc.addUserScript(WKUserScript.injectViewPort())
// Jquery
uc.addUserScript(JQueryScript.core())
// Rangy
uc.addUserScript(RangyScript.core())
uc.addUserScript(RangyScript.classapplier())
uc.addUserScript(RangyScript.highlighter())
uc.addUserScript(RangyScript.selectionsaverestore())
uc.addUserScript(RangyScript.textrange())
// Marker
uc.addUserScript(MarkerScript.css())
uc.addUserScript(MarkerScript.jsScript())
uc.add(coordinator, name: MarkerScript.Handler.serialize.rawValue)
uc.add(coordinator, name: MarkerScript.Handler.erase.rawValue)
let _wkwebview = WKWebView(frame: .zero, configuration: configuration)
_wkwebview.navigationDelegate = coordinator
return _wkwebview
}
func updateUIView(_ webView: WKWebView, context: Context) {
guard data.shouldUpdateView else {
data.shouldUpdateView = false
return
}
context.coordinator.tieFunctionCaller(data: data)
context.coordinator.webView = webView
guard let path: String = Bundle.main.path(forResource: "sample", ofType: "html") else { return }
let localHTMLUrl = URL(fileURLWithPath: path, isDirectory: false)
webView.loadFileURL(localHTMLUrl, allowingReadAccessTo: localHTMLUrl)
}
}

How to add Views on AVCaptureSession ?, like i have avcapturesession running but i cannot add a TextView below it

I am new to SwiftUI, and I was trying to building a app which recognizes objects using Resnet50 model and displays its recognized name, I was able to run the avcapturesession and print the objects name in console but i cant see the TextView when app is running, it always shows the camera fullScreen
This is my Content View
import SwiftUI
import AVKit
import Vision
struct ContentView: View {
#ObservedObject var cameraInfo = CameraViewController()
var body: some View {
VStack {
CameraView()
Text(cameraInfo.objectIdentifier)
}
.edgesIgnoringSafeArea(.top)
}
}
And this is my CameraView which is UIViewControllerRepresentable
struct CameraView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> CameraViewController {
return CameraViewController()
}
func updateUIViewController(_ uiViewController: CameraViewController, context: Context) {
print("Update Called")
}
typealias UIViewControllerType = CameraViewController
}
This is the CameraViewController
final class CameraViewController: UIViewController, ObservableObject,AVCaptureVideoDataOutputSampleBufferDelegate {
var captureSession: AVCaptureSession!
#Published var objectIdentifier: String = ""
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
guard let model = try? VNCoreMLModel(for: Resnet50().model) else { return }
let request = VNCoreMLRequest(model: model) { (finishedRequest, error) in
guard let results = finishedRequest.results as? [VNClassificationObservation] else { return }
guard let firstObservation = results.first else { return }
self.objectIdentifier = firstObservation.identifier
print("DEBUG: firstObs identifier\(firstObservation.identifier),confidence\(firstObservation.confidence)")
}
try? VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:]).perform([request])
}
override func viewDidLoad() {
super.viewDidLoad()
captureSession = AVCaptureSession()
captureSession.sessionPreset = .photo
guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return }
guard let input = try? AVCaptureDeviceInput(device: videoCaptureDevice) else {return}
captureSession.addInput(input)
captureSession.startRunning()
let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
view.layer.addSublayer(previewLayer)
previewLayer.frame = view.frame
let dataOutput = AVCaptureVideoDataOutput()
dataOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "video"))
captureSession.addOutput(dataOutput)
}
}

Profile Image does not appear when I run the app.

Theres no error in my code but ImagevIew image doesn't show
let imageCache = NSCache()
extension UIImageView {
func loadImageUsingCacheWithUrlString(urlString: String) {
//self.image = nil
if let cachedImage = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
self.image = cachedImage
return
}
let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async(execute: {
if let currImage = UIImage(data: data!) {
imageCache.setObject(currImage, forKey: urlString as AnyObject)
self.image = currImage
}
})
}).resume()
}
}

Swift3 Play multiple video files with AVPlayer

I have a little code which allows me to play a local file when I hit a UIButton. But what I want is to play multiple files on 3 different UIButtons because I have 3 video files which I want to attach to my app.
This is the current code:
import UIKit
import AVFoundation
import AVKit
class ViewController: UIViewController {
var playerController = AVPlayerViewController()
var player:AVPlayer?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let videoString:String? = Bundle.main.path(forResource: "Video", ofType: ".mp4")
if let url = videoString {
let videoURL = NSURL(fileURLWithPath: url)
self.player = AVPlayer(url: videoURL as URL)
self.playerController.player = self.player
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func PlayVideo(_ sender: AnyObject) {
self.present(self.playerController, animated: true, completion: {
self.playerController.player?.play()
})
}
}
You can create url for different video file in your button click funtions
#IBAction func Button1Click(_ sender: AnyObject) {
let videoString:String? = Bundle.main.path(forResource: "Video1", ofType: ".mp4")
if let url = videoString {
let videoURL = NSURL(fileURLWithPath: url)
self.player = AVPlayer(url: videoURL as URL)
self.playerController.player = self.player
}
self.present(self.playerController, animated: true, completion: {
self.playerController.player?.play()
})
}
#IBAction func Button2Click(_ sender: AnyObject) {
let videoString:String? = Bundle.main.path(forResource: "Video2", ofType: ".mp4")
if let url = videoString {
let videoURL = NSURL(fileURLWithPath: url)
self.player = AVPlayer(url: videoURL as URL)
self.playerController.player = self.player
}
self.present(self.playerController, animated: true, completion: {
self.playerController.player?.play()
})
}
#IBAction func Button3Click(_ sender: AnyObject) {
let videoString:String? = Bundle.main.path(forResource: "Video3", ofType: ".mp4")
if let url = videoString {
let videoURL = NSURL(fileURLWithPath: url)
self.player = AVPlayer(url: videoURL as URL)
self.playerController.player = self.player
}
self.present(self.playerController, animated: true, completion: {
self.playerController.player?.play()
})
}

UserDefaults.standard not saving swift3 xcode 8

Hello everybody I'm trying to build a simple one view program to call and navigate a voice menu, I cannot get the UserDefaults to properly save between closing of the app. I've also had issue with getting text to display in the UITextField, I would like for it to display if saved on launch, here is a description of vars:
UserInput - text field for employee ID (what needs saving)
Switch - if Save it is 1 save data, if 0 do not
Submit - submit button that should save the data and call.
This is my first iPhone app and any help would be much appreciated!
enter code here
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var UserInput: UITextField!
var SaveIt = true
var employID = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.UserInput.delegate = self;
UserInput.keyboardType = .numberPad
if let current_eid = UserDefaults.standard.string(forKey: "emp_ID") {
UserInput.text = current_eid
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadDefaults() {
let defaults = UserDefaults.standard
if let UserInput = defaults.string(forKey: "emp_ID") {
print(UserInput)
} else {
// focus on the text field if it's empty
UserInput.becomeFirstResponder() }
UserInput.text = defaults.object(forKey: "emp_ID") as! String?
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
#IBAction func Switch(_ sender: UISwitch) {
if (sender.isOn == true) {
SaveIt = true
}
else{
SaveIt = false
}
}
#IBAction func Submit(_ sender: Any) {
if (SaveIt) {
let defaults = UserDefaults.standard
defaults.set(UserInput.text, forKey: "emp_ID")
defaults.synchronize()
}
let phone = "telprompt://1888247889pppp" + UserInput.text! + "p1p1p1p1";
let url = URL(string:phone)!
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else { UIApplication.shared.openURL(url)
}
}
}