I'm trying out the Snap Kit Framework from Snapchat using their sample code but when running the code nothing happens and no error is thrown.
import SCSDKCreativeKit
let snap = SCSDKNoSnapContent()
snap.sticker = SCSDKSnapSticker(stickerImage: UIImage(named: "story_share.png")!)
snap.caption = "Snap on Snapchat!"
snap.attachmentUrl = profileURL.absoluteString
SCSDKSnapAPI().startSending(snap) { (error: Error?) in
print(error)
}
The logs don't indicate an error either:
myapp[853:121028] [SnapKit] Dynamic config update status: success
Things I've tried or insured are correct:
My app is registered online with the correct bundle id, my test snapchat username and the creative kit is selected
the development key is in the Info.plist file as SCSDKClientId
snapchat is in the list of LSApplicationQueriesSchemes
the code runs on the main thread
using their userInteractionEnabled trick doesn't make a difference
I'm using carthage and embed the core and creative framework as usual
What could be the reason why this doesn't work?
I found the disappointing answer that it only works using the deprecated method call:
SCSDKSnapAPI(content: snap).startSnapping() { (error: Error?) in
...
}
I hope that Snapchat fixes their terrible framework in the future. If anyone knows an actual solution, please let me know and I'll accept your answer.
SCSDKSnapAPI() needs to be defined as a class variable. Your code doesn't show the implementation, but I had the same issue when I instantiated SCSDKSnapAPI() in a func() instead of at the Class level.
Here's an implementation that I found which works as intended:
class CreateViewController: UIViewController {
fileprivate lazy var snapAPI = {
return SCSDKSnapAPI()
}()
#IBAction func sendSnap2(_ sender: Any) {
//self.snapAPI = SCSDKSnapAPI() <<DO NOT DO THIS>>
let snap2 = SCSDKNoSnapContent()
view.isUserInteractionEnabled = false
snapAPI.startSending(snap) { [weak self] (error: Error?) in
self?.view.isUserInteractionEnabled = true
if (error != nil) {
print("Error Unknown", error!)
}
else {
print("no error")
}
}
}
Related
I am trying to add the Call Directory Extension to my app to build a simple call blocker, and when I add it to my project and build the app it does not show up in Call Blocking & Identification. I am following along with this tutorial Github CallKit Tutorial
It seems like my extension doesn't exist at all. When reloading my extension I am getting this error
Error reloading extension: The operation couldn’t be completed. (com.apple.CallKit.error.calldirectorymanager error 1.)
Which from I read means the extension does not exist. Here is my reload function
#IBAction func reloadTapped(_ sender: UIButton) {
CXCallDirectoryManager.sharedInstance.reloadExtension(withIdentifier: "com.Unifye.Extension", completionHandler: { (error) in
if let error = error {
print("Error reloading extension: \(error.localizedDescription)")
}
})
}
I am sure I am using the right identifier Image of Identifier
And lastly, my beginRequest function is never being called
class CallDirectoryHandler: CXCallDirectoryProvider {
private let callerData = CallerData()
private func callers(blocked: Bool, includeRemoved: Bool = false, since date: Date? = nil) throws -> [Caller] {
let fetchRequest:NSFetchRequest<Caller> = self.callerData.fetchRequest(blocked: blocked, includeRemoved: includeRemoved, since: date)
let callers = try self.callerData.context.fetch(fetchRequest)
return callers
}
override func beginRequest(with context: CXCallDirectoryExtensionContext) {
context.delegate = self
let defaults = UserDefaults.standard
if let lastUpdate = defaults.object(forKey: "lastUpdate") as? Date, context.isIncremental {
addOrRemoveIncrementalBlockingPhoneNumbers(to: context, since: lastUpdate)
addOrRemoveIncrementalIdentificationPhoneNumbers(to: context, since: lastUpdate)
} else {
addAllBlockingPhoneNumbers(to: context)
addAllIdentificationPhoneNumbers(to: context)
}
defaults.set(Date(), forKey:"lastUpdate")
context.completeRequest()
}
Is there anything else I could be forgetting about or missing? Any help would be greatly appreciated! (I am a big noob so there is a high chance it is something basic and stupid)
Fixed
I simply wiped all my changes, redownloaded the zip, changed the identifiers like Paul mentioned and it started working! Thanks to everyone who helped!
I am trying to add(move forward) 10 second song duration or minus(move backward) 10 second in Spotify player but i am really confused how to add or minus.
When i m trying to use this code the song is not changed duration
// forward button action
#IBAction func moveFrdBtnAction(_ sender: Any) {
SpotifyManager.shared.audioStreaming(SpotifyManager.shared.player, didSeekToPosition: TimeInterval(10))
}
// spotify delegate method seekToPosition
func audioStreaming(_ audioStreaming: SPTAudioStreamingController!, didSeekToPosition position: TimeInterval) {
player?.seek(to: position, callback: { (error) in
let songDuration = audioStreaming.metadata.currentTrack?.duration as Any as! Double
self.delegate?.getSongTime(timeCount: Int(songDuration)+1)
})
}
We are making a music application using the same SDK in both the platforms (Android & iOS), the seekToPosition method of the Spotify SDK is working correctly in the Android version, however, it is not working in the iOS one.The delegate method calls itself but the music stops.
Can you kindly let us know why this scenario is happening, and what should we do to run it on the iOS devices as well.
Can someone please explain to me how to solve this , i've tried to solve this but no results yet.
Any help would be greatly appreciated.
Thanks in advance.
I don't use this API so my answer will be based your code and Spotify's reference documentation.
I think there are a few things wrong with your flow:
As Robert Dresler commented, you should (approximately) never call a delegate directly, a delegate calls you.
I'm pretty sure your action currently results in jumping to exactly 10 seconds, not by 10 seconds.
(As an aside, I'd suggest changing the name of your function moveFrdBtnAction to at least add more vowels)
Anyway, here's my best guess at what you want:
// forward button action
#IBAction func moveForwardButtonAction(_ sender: Any) {
skipAudio(by: 10)
}
#IBAction func moveBackButtonAction(_ sender: Any) {
skipAudio(by: -10)
}
func skipAudio(by interval: TimeInterval) {
if let player = player {
let position = player.playbackState.position // The documentation alludes to milliseconds but examples don't.
player.seek(to: position + interval, callback: { (error) in
// Handle the error (if any)
})
}
}
// spotify delegate method seekToPosition
func audioStreaming(_ audioStreaming: SPTAudioStreamingController!, didSeekToPosition position: TimeInterval) {
// Update your UI
}
Note that I have not handled seeking before the start of the track, nor after the end which could happen with a simple position + interval. The API may handle this for you, or not.
You could take a look at the examples here: spotify/ios-sdk. In the NowPlayingView example they use the 'seekForward15Seconds', maybe you could use that? If you still need 10s I have added a function below. The position is in milliseconds.
"position: The position to seek to in milliseconds"
docs
ViewController.swift
var appRemote: SPTAppRemote {
get {
return AppDelegate.sharedInstance.appRemote
}
}
fileprivate func seekForward15Seconds() {
appRemote.playerAPI?.seekForward15Seconds(defaultCallback)
}
fileprivate seekBackward15Seconds() {
appRemote.playerAPI?.seekBackward15Seconds(defaultCallback)
}
// TODO: Or you could try this function
func seekForward(seconds: Int){
appRemote.playerAPI?.getPlayerState({ (result, error) in
// playback position in milliseconds
let current_position = self.playerState?.playbackPosition
let seconds_in_milliseconds = seconds * 1000
self.appRemote.playerAPI?.seek(toPosition: current_position + seconds_in_milliseconds, callback: { (result, error) in
guard error == nil else {
print(error)
return
}
})
})
}
var defaultCallback: SPTAppRemoteCallback {
get {
return {[weak self] _, error in
if let error = error {
self?.displayError(error as NSError)
}
}
}
}
AppDelegate.swift
lazy var appRemote: SPTAppRemote = {
let configuration = SPTConfiguration(clientID: self.clientIdentifier, redirectURL: self.redirectUri)
let appRemote = SPTAppRemote(configuration: configuration, logLevel: .debug)
appRemote.connectionParameters.accessToken = self.accessToken
appRemote.delegate = self
return appRemote
}()
class var sharedInstance: AppDelegate {
get {
return UIApplication.shared.delegate as! AppDelegate
}
}
Edit1:
For this to work you need to follow the Prepare Your Environment:
Add the SpotifyiOS.framework to your Xcode project
Hope it helps!
I've been stuck on a bug since last Monday, so I'm asking for help now ..
Contacts and Micriohpone request access does not work on iOS 9. I use this piece of code in order to request access to contacts :
let contactsStore = CNContactStore()
func requestAccess(completionHandler: #escaping (Permission) -> ()) {
self.contactsStore.requestAccess(for: .contacts, completionHandler: { (granted, error) in
if granted {
completionHandler(.granted)
} else {
completionHandler(.denied)
}
})
}
This function is called, no problem with that, the problem is it always return .denied and an error set with "Access denied", even though no alert has been shown to the user. The same with microphone.
The key 'Privacy - Contacts Usage Description' is present in my Info.plist
EDIT :
I also know that when the user denied once the usage it is not shown anymore, but the other problem is that there is not "switch" in the settings section of the app. I tried to restore the device (Working on simulator as I don't have a real iOS 9 device), but still the same behaviour.
This code works perfeclty on iOS 10 and iOS 11. But no chance on iOS 9
If you could help me on this issue that would be awesome.
Thanks !
I tried this on 9.3 in the simplest way imaginable, and I did get a prompt:
import UIKit
import Contacts
class ViewController: UIViewController {
let contactsStore = CNContactStore()
override func viewDidAppear(_ animated: Bool) {
DispatchQueue.main.async {
self.requestAccess(completionHandler: { (permission) in
print("The user said \(permission)")
})
}
}
func requestAccess(completionHandler: #escaping (Permission) -> ()) {
self.contactsStore.requestAccess(for: .contacts, completionHandler: { (granted, error) in
if granted {
completionHandler(.granted)
} else {
completionHandler(.denied)
}
})
}
}
enum Permission {
case granted
case denied
}
This works fine. I think the issue is that you already denied it.
The only solutions are:
Change the bundle id, which will make your app act as a different one
Reset your device/simulator (easier if a simulator of course)
Change the privacy setting from Off to On
For end users, I've seen the UI prompt the user to change the setting if they see "denied".
You can do that like this:
self.requestAccess(completionHandler: { (permission) in
print("The user said \(permission)")
if ( permission == .denied ) {
let urlStr = UIApplicationOpenSettingsURLString
if let url = URL(string:urlStr) {
UIApplication.shared.openURL(url)
}
}
})
I would like to know if you can set the code that enables the accessory programmatically? I in this moment use:
import UIKit
import Foundation
import HomeKit
let homeManager = HMHomeManager()
func addAccessory () {
if let home = homeManager.primaryHome {
for room in home.rooms {
if room.name == "Kitchen" {
homeManager.primaryHome?.addAccessory(accessory, completionHandler: { (error) -> Void in
if error != nil {
print("ERROR 1 \(error?.localizedDescription)")
}else {
self.homeManager.primaryHome?.assignAccessory(accessory, toRoom: room, completionHandler: { (error) -> Void in
if error != nil {
print("ERROR 2 \(error?.localizedDescription)")
} else {
print("Accessory Add successfully")
}}}}
}
I would not use the usual view offered by Apple to enter the code.
At this point in time, there is no reference in HomeKit documentation to being able to override the default screens that are displayed when using the HMHome addAccessory method.
I was looking for this myself and have not found anything and have also posed the question on the Apple Developer's HomeKit forum. If I hear differently on the forums, I'll post back here.
I am attempting to integrate some JSSAlertViews within one of my ViewControllers, but for some odd reason, when I run my project, the alert views do not show. So to make sure it wasn't any error with coding, I created an exact pseudo project to replicate the ViewController of my original project, down to it's UI elements on the storyboard. I copied the exact code from my original project onto the new ViewController, ran it, and everything worked. Im stuck onto figuring out, why won't it work on my original project??
here is the logic i used:
#IBAction func resetPass(sender: AnyObject) {
actview.hidden = false
actview.startAnimating()
PFUser.requestPasswordResetForEmailInBackground(emailReset.text) {
(success:Bool, error:NSError?) ->Void in
if(success){
let yesMessage = "Email was sent to you at \(self.emailReset.text)"
dispatch_async(dispatch_get_main_queue()) {
self.actview.stopAnimating()
JSSAlertView().success(self, title:"Great Success", text:yesMessage)
}
}
if(error != nil){
let errorMessage:String = error!.userInfo!["error"] as! String
dispatch_async(dispatch_get_main_queue()) {
self.actview.stopAnimating()
JSSAlertView().warning(self, title:"Woah There", text:errorMessage)
}
}
}
}
I set a breakpoint on a call of one of the JSSAlertView's , expanded the element in my console and got this :
Is this a memory management error and reason why they aren't visible? how do i fix this?
here is the Git if you want to check it out, its awesome: https://github.com/stakes/JSSAlertView
Anything with the UI needs to be done on the main thread, and you're calling the Parse function on the background thread (via requestPasswordResetForEmailInBackground).
So to get your alerts to appear on the main thread, you need to add a little GCD magic:
#IBAction func resetPass(sender: AnyObject) {
actview.hidden = false
actview.startAnimating()
PFUser.requestPasswordResetForEmailInBackground(emailReset.text) {
(success:Bool, error:NSError?) ->Void in
if(success){
self.actview.stopAnimating()
let yesMessage = "Email was sent to you at \(self.emailReset.text)"
dispatch_async(dispatch_get_main_queue()) {
self.successMessage(yesMessage)
}
};
if(error != nil){
self.actview.stopAnimating()
let errorMessage:String = error!.userInfo!["error"] as! String
dispatch_async(dispatch_get_main_queue()) {
self.failureMessage(errorMessage)
}
}
}
}
See my addition of the "dispatch_async(dispatch_get_main_queue())" lines?