Offline playlists using CocoaLibSpotify - ios

I am using CocoaLibSpotify in an iOS application. When I set markedForOfflinePlayback to YES on an instance of SPPlaylist the offlineStatus almost immediately changes to SP_PLAYLIST_OFFLINE_STATUS_YES for the playlist and the tracks in the playlist. However, the offlineDownloadProgress is 0.0 all the time.
The tracks have clearly not been cached. First and foremost, it would take much longer to cache them. Secondly, when I put my device in airplane mode and try to play one of the tracks marked as offline, no audio is played.
Does anyone have an idea what I might be doing wrong?

The most common cause for this is not shutting down CocoaLibSpotify properly when the application goes into the background - this can cause the cache to end up in an odd state that will cause offline syncing to fail. To avoid this, when your app goes into the background, you should start a background task, begin the logout process then end the task when logout is complete. The Empty CocoaLibSpotify Project sample project demos this.
Also, make sure you're updated to the latest version of CocoaLibSpotify - it contains an update to the underlying libSpotify library that makes offline syncing quite a lot more reliable. You still need to perform the proper backgrounding technique, though.
Finally, have a look at the Offline Syncing Mac sample project. It lets you see the offlining process in a visual way.

Related

Can HTML5 in the browser play continuous audio on iOS lock screen?

I have been trying to track this down and there doesn't seem to be a consistent answer. If I have a website that tries to play multiple songs in a row (think playlist) using the HTML 5 audio element, can it continue to work on the iOS lock screen?
For some background, this answer seems to indicate it may be possible. But then this article suggests it is not.
I tried following the closest example of what Apple recommends, as found here, to replicate this. I am using plain, vanilla javascript and HTML, nothing fancy. I copied their example exactly and just substituted the audio tag for the video one, picking two random mp3 songs. All it does is wait for one song to end, then switch the src, load, and play the next track.
When I hit Play on the website, I then lock the iPhone. The first song will play, then stop. It does not continue to the next song.
If the website is open to the page, it will properly transition to the next song. On Android, it will continue to the next song even if the phone is locked.
I tried this with iOS 11 and 12. Neither worked. I have read many differing answers about how javascript is stopped when the website isn't in the foreground, and how iOS requires user interaction to play audio (even going from one song to the next). So it doesn't seem like this would work. But then other answers out there seem to indicate this is possible.
Is there a definitive yes or no? Am I doing something wrong here? Or is it just not possible?
There are multiple issues, which is causing some of the confusion.
First track plays, second does not due to user permission
If the first track was started with user permission, then the only way you can switch to a new track via script is with Apple's recommendation. Handle the ended event and swap in a new src, and call .play() before the callback completes. Otherwise, your code will not have permission to start the new audio.
Cannot get to ended event due to time-constrained source (#t=5,10)
Say you have a 30-second audio file and you tell the browser to only load seconds 5 through 10, via something like #t=5,10 at the end of the URL. When you reach 10, a paused event will fire, not ended. Therefore, it isn't possible to go on to the next track normally, as this event is not "blessed" by Apple to count as a relay of the previous user interaction.
I got around this by having my JavaScript check the currentTime repeatedly, and when it crossed a threshold, seek it to the duration (end) of the file myself. This allows ended to fire normally.
iOS doesn't allow scripts to run after the screen is locked or other apps are in use
This one is a real problem to debug, since it doesn't turn up in any of the simulators. In any case, you're right, your JavaScript is going to get suspended so even if you follow Apple's recommendations, you're out of luck. Or, are you?
A hack... set up a ScriptProcessorNode on a Web Audio context. Set the buffer size to like 512 samples or something. Then, on script process, force a timeupdate event for your Audio Element. This keeps your JavaScript there ticking away. ScriptProcessorNode has to have special privileges here, by its nature.
Apple: If you read this, please fix your browser. It would be great if we didn't have to hack around things to make something as simple as an audio playlist to work. Other browsers don't have nearly this level of problems.

Tracking device useage on iOS

I've been using this app called Moment that tracks how much time I spend on my device every day. I think it's very cool, and at the same time am very curious how it works. I don't have tons of mobile development experience, as I've mainly built web apps, but I'm curious how this kind of functionality could be achieved.
I did a few quick Google searches and found that iOS does have some support for background task execution. The functionality lies in four categories:
Play audio
Receive location updates
Perform finite-length tasks
Background fetch
It looks like I can't do anything tricky using audio callbacks, as Apple will reject the app, but I'm wondering if I can do something with (3).
They do it using Custom Profiles.

How to detect data being per app basis on iOS

I recently came across an app in the app store called Dataman Pro. It has a feature that lets you see the data usage per app basis (see the attached screenshot). I have been wondering what is it doing to get this sort of information.
See this post about getting the list of installed apps, and this git project.
Then about usage tracking:
If you wondered about any public APIs that give you network statistics out of the box - there's nothing there.
DataMan it self is an app that used to work in the background all the time, and bind to the network interfaces to track network usage. Which is one of the reasons that its data is never 100% accurate as it is not guaranteed to always work in the background. This is also the reason Apple kicked it from the AppStore after a few versions...
Now that app has returned, if I understand correctly, after making a few changes: Mainly avoiding "hacks" to stay in background, and using Location Services to get back online when the user moves around. I guess this is another hack but one that Apple did not oppose to, yet.
Edit:
After looking around the web for a bit, it seems that Apple found that trick also, and removed many apps from the AppStore due to staying in the background by using location. I guess right now it's not working more than 10 minutes in the background, so you open it when you want to measure current Activity, and it stops measuring after 10 minutes.
About the tracking code itself, its mainly C code, using CFNetwork framework, and you can find some answers on stackoverflow on this subject.
More, in response to comment:
Well, the part about seeing the installed apps list, and foreground app, is not exactly private APIs, but private plist, as you mentioned.
Apps which access private files do get through from time to time. When Apple finds that some "private" files are accessed and need to be kept safer - they change it in an iOS update, like they did with the call history file, which is sensitive. Old apps tended to use (around iOS <= 3.3) the call history db to do some stats, and on iOS4 they were obsolete by the file moving to a secure location.
Reading "private" files which are unprotected is pretty easy to do without getting caught by automatic analyzers.
When you know which is the foreground app, and you can count current network usage, you can associate it with the app... And get an estimation. So this is how they do it, most likely.
However, The techniques change from time to time, due to Apple re-reviewing apps and their own policies, and due to API changes, and if you track the history of such apps and even this specific app - you will see that from time to time they get kicked off of the AppStore and return with a twist. They adjust... So no technique is reliable and this is a major headache to maintain, which is probably why the developer charges 9.99$ for it. I would.

iOS Background Mode

I have a question about running an app in the background.
I know about how to do it, but Apple does not like the way I'm doing it.
To get you on the same page, I have a security app, and I need to it monitor the device even when it is in the background. It is sort of like a burglar alarm.
I was using background audio mode, thinking it would be okay because I will be playing a sound when it is triggered. Needless to say, Apple didn't like that.
So I added a ping! It pings while active, therefor playing background audio while in the background.
Once again, they didn't like that either.
My app monitors the accelerometer as well (but not always, only when chosen by the user).
My question is, how are apps like Skype, and other similar apps able to turn the status bar red, and stay in the background? (Even some alarm apps will do this, without playing any audio or anything).
Also I can't use the notification system because it does not update fast enough if I'm monitoring the battery level. For my app I need immediate response.
I have also searched around tirelessly for this answer before I posted my question (the answers I have found, do not work for me..) :(
I would greatly appreciate any insight on this, Thanks in advance!
(If you need anymore information, please ask!)
From what I can tell from their documentation, it seems that the only way you can maintain a persistent background connection is by using one of their seven background mode keys, which I can see you've been trying since you registered for background audio. I know some alarm apps as well that use this feature (e.g. Sleep Cycle), and my assumption is that they are also using background audio mode, considering the other six modes are not remotely close to what they would need it for.
I think Apple's reasoning might be that these apps are allowed to do so, because their app is designed to be used when the user is not using the phone actively (i.e. when they're sleeping), and requires the audio to wake the user up, whereas if you are running a security app that wants to be active at all times, it may interfere with other features the user may use like Skype. The red bar will also persist at the top of the device at all times when the user is using it, which they may mistake for something that is still playing since usually when a red bar appears it means to the user that they are still actively using something. Again, I think wake-up alarm apps and others like them that aren't using persistent audio are able to get away with this since they are designed for use when the phone is inactive, so having the persistent red bar when the app is not visible is less of an issue.
In some other cases, like Nike+ (discussed here) and likely pedometers, they seem to be using the location background mode, since they often also track where you went and need to know distance. In that discussion I linked to, it looks like others were able to get accelerometer updates by registering for a background mode that applied to them. Have you tried registering for location movements? One downside I can see to that is it might drain battery life quicker, but if you check location infrequently it might not be too bad? Another is that I don't think you can directly play audio when in location background mode, but you could try to trigger a sound notification? :) That might be a nice workaround for it if that works for your app.
Again, the reasoning I have for why these apps are able to do it is just based on how I've seen other apps operating, and Apple may have different reasons for why it accepts them, but that was my best way of thinking why your app got rejected for using those modes while the others are able to do it. If location isn't what you're looking for, unfortunately I'm not sure from what it sounds like your app is doing that you'd be able to operate it continuously in the background in the way you're expecting.
Being responsive is a need for every app. Users want to have apps which have their content ready when they open it, so developers should use Background Modes to make their apps more user friendly.
Turning on the Background Modes capability
Go to Xcode and open your project.
In your app target, navigate to Capabilities tab.
Turn on Background Modes.
Background Fetch
Background fetch is a new mode that lets your app appear always up-to-date with the latest information while minimizing the impact on battery. You could download feeds within fixed time intervals with this capability.
To get started:
1- Check Background Fetch in capabilities screen in Xcode.
2- In application(_:didFinishLaunchingWithOptions:) method in AppDelegate,
Reference: https://medium.com/#javedmultani16/background-modes-in-ios-3da25b9e6474
You can use background modes only if you actively use the activity that keeps the app awake: e.g. continuously playing audio is a valid use of the audio background key. They'll look pretty hard at whether you really need the access you request, and if not they'll reject you (as you've already found out), as background services drain the battery considerably more than others.
From the docs:
These keys should be used sparingly and only by apps providing the indicated services.
Short story: I think you're out of luck with your proposed implementation.

Long time downloading in iOS app

How many issues need to be considered carefully if a large of content need to be downloaded in an iOS app ?
Here are my known issues:
Network , No limits for Wifi, but Apple has limit policy for cellular network. enter link description here
Background execution. Apple introduced multitasking for several cases, but no for downloading large content background. Here is a good analysis.
Newsstand provides good solution for this. But does that mean you need follow the Newsstand approach ? We do not want to build an newsstand type app.
What else issues do you think ? and what is the best solution for this sort of problem ?
I would lazy load only data as needed. When the user requests an area load revenant data.
If you want to preload do it in the background. I have seen 1.6Gb apps with lots of videos, embedded in main bundle, but that was for sales app that needed to have all videos ready to go and could not assume any active network connection.
Download the data you need in a background thread while your app is running. If your app is terminated or suspended before you get all the data, resume where you left off the next time the app is running. There are a number of ways that you can do that; one good one is to break your data up into smaller chunks that can be downloaded sequentially.

Resources