I was using a UIActivityViewController instance in several previous versions of an app in order to share content through AirDrop, and other services. And now, without even recompiling, when running the app in iOS 11 Beta, the dialog (UIActivityViewController instance) shows the following row with the message "Unable to load":
Here is the code:
let handlerOk = { () -> Void in
let activityItems = [NSURL(fileURLWithPath: fullPath, isDirectory: true)]
self.viewControllerShare = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
if let viewControllerShare = self.viewControllerShare {
viewControllerShare.popoverPresentationController?.sourceView = sender
let excludedActivities = [
UIActivityType.postToFacebook,
UIActivityType.postToTwitter,
UIActivityType.postToWeibo,
//UIActivityType.message,
//UIActivityType.mail,
UIActivityType.print,
UIActivityType.copyToPasteboard,
UIActivityType.assignToContact,
UIActivityType.saveToCameraRoll,
UIActivityType.addToReadingList,
UIActivityType.postToFlickr,
UIActivityType.postToVimeo,
UIActivityType.postToTencentWeibo,
UIActivityType.openInIBooks
]
viewControllerShare.excludedActivityTypes = excludedActivities
self.present(viewControllerShare, animated: true, completion: nil)
}
}
Right now I'm compiling with XCode 9 in Swift 4, but I don't think this is relevant since as said, if an older version of the app is run in iOS 11 (compiled with XCode 8.somenthing or even downloading the binary from TestFlight) the problem is the same. So this really looks like an iOS 11 API problem...
Is there anything new regarding the dialog initialization that may prevent the "Unable to load" row to appear?
EDIT: I tested a third party app (from Apple) that uses the same sharing dialog, and found that that row belongs to iCloud. But I'm not using iCloud in my app, so the previous UIActivityViewController behaviour was correct: it just did not show anything. So I made an experiment: disabled from iOS' Settings the iCloud permission for that third party app, and it showed the same unkind "Unable to load" message. I hope this is not the way that the final iOS 11 version works, and that it's just a Beta problem.
That said, workarounds are still welcome! Thanks!
Related
I am using Java JDK 11.0.8 ("Installed JREs" under Eclipse is set to jdk-11.0.8), Eclipse 2020-06, and Codename One 6.0.0.
I have recently switched from JDK 8 to JDK 11 and noticed that playing sounds option in my app does not work anymore...
Note that I uncheck "Java 8" when I create my app and I am only trying to work things out in the simulator (I am not trying to deploy the app to an actual mobile device).
I want to play a "regular sound" (I want to play a sound from beginning to end, and when it ends I do not need to replay it from the beginning) and also a "looping sound" (the sound should come to its beginning when it ends and hence, I can continuously play it in the background).
Hence I have two questions:
Question1 - About "regular sounds"
I would like to create Media object just once and then re-use it whenever I need to play the same regular sound.
For that purpose I am encapsulating a Media creation inside a class as follows:
public class RegularSound {
private Media m;
public RegularSound(String fileName) {
try{
InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/"+fileName);
m = MediaManager.createMedia(is, "audio/wav");
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void play() {
m.setTime(0);
m.play();
}
}
Then I instantiate the RegularSound object and play it as follows:
mySound = new RegularSound("example.wav");
mySound.play();
Please note that example.wav is copied directly under the "src" directory of my project.
This code used to work with JDK 8, but with JDK 11, I get the following build errors:
Exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: javax/media/ControllerListener
at com.codename1.impl.javase.JavaJMFSEPort$1.run(JavaJMFSEPort.java:67)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.lang.ClassNotFoundException: javax.media.ControllerListener
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at java.base/java.lang.ClassLoader.findSystemClass(ClassLoader.java:1247)
at com.codename1.impl.javase.ClassPathLoader.findClass(ClassPathLoader.java:269)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
at com.codename1.impl.javase.ClassPathLoader.loadClass(ClassPathLoader.java:115)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at com.codename1.impl.javase.ClassPathLoader.loadClass(ClassPathLoader.java:107)
... 14 more
Question2- About "looping sounds"
For looping sound I have created another class as follows:
public class LoopingSound implements Runnable{
private Media m;
String fileName;
public LoopingSound(String fileName){
try{
InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/"+fileName);
m = MediaManager.createMedia(is, "audio/wav",this);
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void pause()
{
m.pause();
}
public void play()
{
m.play();
}
public void run() {
m.setTime(0);
m.play();
}
}
But I again get build errors when I instantiate an object of LoopingSound and try to play it...
So could you please let me know how to change code for regular and looping sounds so that I do not receive above-mentioned errors when using JDK 11?
UPDATE
Thanks for the reply #shai-almog. I have installed CEF. But I am receiving some messages on the console in runtime and I can't hear the sound playing... I run the following code:
try {
InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/example.wav");
Media m = MediaManager.createMedia(is, "audio/wav");
m.play();
} catch (IOException e) {
e.printStackTrace();
}
and I receive the following messages on console when I run this code (it throws an exception at the end):
Adding CEF to classpath
Retina Scale: 2.0
CEF Args: [--disable-gpu, --disable-software-rasterizer, --disable-gpu-compositing, --touch-events=enabled, --enable-media-stream, --device-scale-factor=4, --force-device-scale-factor=4, --autoplay-policy=no-user-gesture-required, --enable-usermedia-screen-capturing]
Using:
JCEF Version = 83.4.0.260
CEF Version = 83.4.0
Chromium Version = 83.0.4103.106
AppHandler.stateHasChanged: INITIALIZING
initialize on Thread[AWT-EventQueue-0,6,main] with library path C:\Users\pmuyan\.codenameone\cef\lib\win64
Added scheme search://
Added scheme client://
Added scheme cn1stream://
DevTools listening on ws://127.0.0.1:8088/devtools/browser/591d3502-6fd6-4997-9131-9a2a352e47b1
AppHandler.stateHasChanged: INITIALIZED
Running ready callbacks
Exception in thread "AWT-EventQueue-0" Address changed to data:text/html,%3C!doctype%20html%3E%3Chtml%3E%3Chead%3E%3Cstyle%20type%3D'text%2Fcss'%3Edocument%2C%20body%20%7Bpadding%3A0%3Bmargin%3A0%3B%20width%3A100%25%3B%20height%3A%20100%25%7D%20video%2C%20audio%20%7Bmargin%3A0%3B%20padding%3A0%3B%20width%3A100%25%3B%20height%3A%20100%25%7D%3C%2Fstyle%3E%3C%2Fhead%3E%3Cbody%3E%3Caudio%20id%3D'cn1Media'%20width%3D'640'%20height%3D'480'%20style%3D'width%3A100%25%3Bheight%3A100%25'%20src%3D'https%3A%2F%2Fcn1app%2Fstreams%2F1'%2F%3E%3Cscript%3Ewindow.cn1Media%20%3D%20document.getElementById('cn1Media')%3Bfunction%20callback(data)%7B%20cefQuery(%7Brequest%3A'shouldNavigate%3A'%2BJSON.stringify(data)%2C%20onSuccess%3A%20function(response)%7B%7D%2C%20onFailure%3Afunction(error_code%2C%20error_message)%20%7B%20console.log(error_message)%7D%7D)%3B%7Dcn1Media.addEventListener('pause'%2C%20function()%7B%20callback(%7B'state'%3A'paused'%7D)%7D)%3Bcn1Media.addEventListener('play'%2C%20function()%7B%20callback(%7B'state'%3A'playing'%7D)%7D)%3Bcn1Media.addEventListener('ended'%2C%20function()%7B%20callback(%7B'state'%3A'ended'%7D)%7D)%3Bcn1Media.addEventListener('durationchange'%2C%20function()%7B%20callback(%7B'duration'%3A%20Math.floor(cn1Media.duration%20*%201000)%7D)%7D)%3Bcn1Media.addEventListener('timeupdate'%2C%20function()%7B%20callback(%7B'time'%3A%20Math.floor(cn1Media.currentTime%20*%201000)%7D)%7D)%3Bcn1Media.addEventListener('volumechange'%2C%20function()%7B%20callback(%7B'volume'%3A%20Math.round(cn1Media.volume%20*%20100)%7D)%7D)%3Bcn1Media.addEventListener('error'%2C%20function()%7B%20var%20msg%20%3D%20'Unknown%20Error'%3B%20try%20%7Bmsg%20%3D%20cn1Media.error.message%20%2B%20'.%20Code%3D'%2Bcn1Media.error.code%3B%7Dcatch(e)%7B%7D%20callback(%7B'error'%3A%20msg%7D)%7D)%3B%3C%2Fscript%3E%20%3C%2Fbody%3E%3C%2Fhtml%3E
UPDATE 2
I could manually add Open JavaFX 11 to Eclipse and to Codename One app running under Eclipse while using JDK 11 as follows:
Step1) Create JavaFX11 user library under Eclipse
Download JavaFX 11 from https://gluonhq.com/products/javafx/
unzip it -> creates javafx-sdk-11.0.2 folder
Create a User Library: Eclipse -> Window -> Preferences -> Java -> Build Path -> User Libraries -> New.
Name it JavaFX11.
Hit "Add External JARs" and include all the jars under javafx-sdk-11.0.2\lib
Step 2) Add the JavaFX11 library to the project:
Right click on project.
Select Build path -> Configure Build Path
Goto Library tab->Add Library->User Library->Check JavaFX11->Apply and Close
Now, I can hear sounds playing in my Codename One application.
However, I need to run my application from command prompt and regular command line to run the apps does not work anymore (the app cannot find the JavaFX related classes from the command prompt and I get the same errors listed above). So could you please tell me how to modify the command line so that Codename One project that uses JavaFX would run from command prompt?
Here is the regular command line I use:
java -cp dist\Proj.jar;JavaSE.jar com.codename1.impl.javase.Simulator com.mycompany.hi.Main
BTW, I have tried to add javafx.media.jar under javafx-sdk-11.0.2\lib to the classpath (-cp) in the command line, but this did not work...
UPDATE 3
We have solved the issue by using the following command line:
java --module-path C:\javafx-sdk-11.0.2\lib\ --add-modules= ALL-MODULE-PATH -cp dist\Proj.jar;JavaSE.jar com.codename1.impl.javase.Simulator com.mycompany.hi.Main
(where C:\javafx-sdk-11.0.2\lib\ is our )
Thanks!
The TL;DR
Either install CEF as explained here or switch to ZuluFX 11 for your VM.
The explanation:
This used to work until we integrated CEF support we would download JavaFX dynamically for JDK 11 installs but this caused a lot of related problems. So we decided to migrate to CEF, this is still in progress and while it's ongoing JavaFX dynamic download is broken. Once it's done CEF will be auto-installed and this will be seamless again.
This impacts browser component and media which are the two components implemented by JavaFX.
I am trying to develop an application using SiriKit to get the car door lock status and set the same from Siri. I followed this blog https://www.appcoda.com/sirikit-introduction/ and did all the setup replacing the INStartWorkoutIntent with INGetCarLockStatusIntent.
But when i try to set the vocabulary for carName, the application is getting crashed with following exception,
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Illegal attempt to provide vocabulary of type INVocabularyStringTypeCarName by an app that does not handle any intents that could use that type of vocabulary'
The source code that i am using to set the vocabulary is,
INPreferences.requestSiriAuthorization { (status) in
}
INVocabulary.shared().setVocabularyStrings(["benz", "bmw", "audi"], of: .carName)
In AppDelegate, i have added the following method,
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
guard let intent = userActivity.interaction?.intent as? INGetCarLockStatusIntent else {
print("AppDelegate: Start Workout Intent - FALSE")
return false
}
print("AppDelegate: Start Workout Intent - TRUE")
print(intent)
return true
}
Also created the extension for intent handler and implemented INSetCarLockStatusIntentHandling, INGetCarLockStatusIntentHandling protocols. I am getting this issue when i try to run it in iPhone 10.
Check, if in TARGETS of your project in Build Phases->Embed App Extensions added your Siri Extension. Maybe if you replace the INStartWorkoutIntent with INGetCarLockStatusIntent, old INStartWorkoutIntent remained there.
My crash fix this.
I was facing a similar issue. Make sure your extension's Deployment Target is set to appropriate iOS version. Creating an extension with the latest Xcode (at the moment 10.1) will set the Deployment Target to 12.1 and thus cause crash when run on iOS 10. So you should change it to your desired minimum.
I have a music app that uses the MPMusicPlayerController.
I originally wrote it using the systemMusicPlayer option under iOS 9.
I had some trouble with the player not shutting down correctly under certain circumstances so I switched to the appplicationMusicPlayer
(see Quitting app causes error "Message from debugger: Terminated due to signal 9")
However, as an application player, I can't get a lot of the benefits like control center handling, bluetooth data display, etc.
So, I switched back to the systemMusicPlayer.
I have also changed to Xcode 9.2 and a compile target of iOS 10.3.
Now when I run my app, it can take several seconds for it to respond to controls like play/pause or next/previous. My whole UI is painfully unresponsive.
I tried switching back to applicationMusicPlayer, recompiled, and sure enough - the UI is at normal speed.
So now I'm in a crappy position - with systemMusicPlayer, the app is barely usable, but with applicationMusicPlayer I lose a ton of capabilities.
This seems directly related to either iOS 11.2.2 on my iPhone, or something to do with targeting iOS 10.3+
Does anyone have any information about what is going on and how to fix it
EDIT:
I created a very basic player and it seems to work fine in either mode, so now I'm puzzled - I'll be testing other MP commands to see what the
issue is but since even my UI slows down I'm not sure.
EDIT 2:
I believe I've found the culprit to be NotificationCenter, and also getting States from the MPMusicPlayerController. I've updated my sample code below which shows the problem. Once running, clicking the 'next' button will be slow sometimes, but clicking 'previous' can cause delays of up to two seconds!!
Here is the basic code if you want to create a simple player.
Be sure to add three buttons in the storyboard and connect them accordingly.
//
// ViewController.swift
// junkplayer
//
import UIKit
import MediaPlayer
let notificationCenter = NotificationCenter.default
let myMP:MPMusicPlayerController = MPMusicPlayerController.systemMusicPlayer
//let myMP:MPMusicPlayerController = MPMusicPlayerController.applicationMusicPlayer()
class ViewController: UIViewController {
#IBOutlet weak var xxx: UIButton!
#IBOutlet weak var nextbut: UIButton!
#IBOutlet weak var prevbut: UIButton!
var qrySongs = MPMediaQuery()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
myMP.repeatMode = MPMusicRepeatMode.none
myMP.shuffleMode = MPMusicShuffleMode.off
myMP.prepareToPlay()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
stopMPNotifications()
startMPNotifications()
}
#IBAction func nextbut(_ sender: Any) {
myMP.skipToNextItem()
}
#IBAction func prevbut(_ sender: Any) {
myMP.skipToPreviousItem()
}
#IBAction func playbut(_ sender: UIButton) {
qrySongs = MPMediaQuery.songs()
myMP.setQueue(with: qrySongs)
myMP.play()
}
func startMPNotifications(){
notificationCenter.addObserver(self, selector: #selector(showNowPlaying), name: .MPMusicPlayerControllerNowPlayingItemDidChange, object: myMP)
notificationCenter.addObserver(self, selector: #selector(handlePlayState), name: .MPMusicPlayerControllerPlaybackStateDidChange, object: myMP)
myMP.beginGeneratingPlaybackNotifications()
}
func stopMPNotifications(){
notificationCenter.removeObserver(self, name: .MPMusicPlayerControllerPlaybackStateDidChange, object: myMP)
notificationCenter.removeObserver(self, name: .MPMusicPlayerControllerNowPlayingItemDidChange, object: myMP)
myMP.endGeneratingPlaybackNotifications()
}
#objc func handlePlayState(){
if myMP.playbackState == .playing {
print("handlePlayState playback state = playing")
}else{
print("handlePlayState playback state NOT playing")
}
print("handlePlayState going to shownowplaying")
showNowPlaying()
}
#objc func showNowPlaying(){
if myMP.nowPlayingItem != nil {
print("shownowplaying nowplaying not null")
}
}
}
The app seems to lock up once you start playing, but if you swipe up to show the Control Centre then dismiss it, the app starts working fine immediately.
I am having the same problem. I think it’s something wrong with the API. It's especially slow for large queries. But you can put a predicate on the quart, that allows no cloud music to go on it.
For anyone browsing this thread in the future, this was a known bug within all versions of iOS 11.2. It affected anyone using the systemMusicPlayer.
Apple sure does love to discourage us third party music app developers, eh? ;)
Regardless of my conspiracy theories (and I'm sure you have yours too), this bug was fixed in iOS 11.3.
We warn users on iOS 11.2 about the bug and recommend that they upgrade to iOS 11.3 for a (more or less) lag-free experience.
I ran into this problem today - working code just stopped running correctly, but I found a (partial) workaround:
\\Do anything that updates (like changing the song title in the UI) in the selector called by this notification
NotificationCenter.default.addObserver(self, selector: #selector(remoteMusicChange), name: NSNotification.Name.MPMusicPlayerControllerNowPlayingItemDidChange, object: nil)
The issue is that calls to say go to the next track for systemMusicPlayer are no longer (always) happening immediately. If you wait for the notification, at least you can be sure systemMusicPlayer has updated.
The problem with this is sometimes it can take a perceptibly long time for that notification to fire (and sometimes it's instant).
EDIT: https://forums.developer.apple.com/thread/96287 I am guessing this is related to these issues
EDIT2: Tested another related issue quickly in iOS12 and the problem no longer existed (changing playback speed) and the pauses when changing songs went away.
My app crashes with NullPointerException, since the android calendar does not return a Collection of calendar names from the dc.getCalendars(); function from the CN1 Calendar Lib, even though it is working to this point on the iOS iphone version.
Device Calendar dc = DeviceCalendar.getInstance();
Collection<String> calNames = dc.getCalendars();
String [] nameArray = calName.toArray(new String[calName.size()]);
Its throwing me an NullPointerException for the 3rd line because calName is a null object and I cant use size() on it. Again, the code IS working on iPhone, so it seems there is a problem with android.
Thanks in advance.
The javadocs for that method say that getCalendars() will return null if you don't have permission
https://github.com/sidiabale/codenameone-calendar/blob/master/CN1Calendar/src/com/codename1/calendar/DeviceCalendar.java#L91
You'll need to add the permissions using the android.xpermissions build hint.
codename1.arg.android.xpermissions=<uses-permission android:name="android.permission.READ_CALENDAR"/> <uses-permission android:name="android.permission.WRITE_CALENDAR"/>
And it looks like you also need to set android.targetSDKVersion=21
See this SO thread for a related issue.
Just updated my XCode from 4.6 to 5, and along with it the iOS7 SDK.
I noticed that all operations (e.g. Predicate filters etc) I attempt to perform on empty NSArray or NSMutableArray cause an exception (NSInvalidArgumentException) when running my app in the simulator for either iOS 5.1 or iOS 7 (still struggling to download iOS 6.1)
My arrays are instantiated (so they are not Nil), but they have 0 entries.
So code that used to work fine in XCode 4.6 now crashes, and I have to add an extra IF to check if the array.count == 0 before running that line of code all over my app. (Monumental task)
When I download my app (version I published with XCode 4.6) from the AppStore to an iOS7 device, it works just fine.
Anyone else also experiencing this?
based on this code, I think the value stored in [defaults objectForKey:#"Wards"] is not an array, please double check the value
NSArray *SelectedWards = [[NSArray alloc]initWithArray:[defaults objectForKey:#"Wards"]];
you may use following code to check
if(![[defaults objectForKey:#"Wards"] isKindOfClass:[NSArray class]])
{
NSLog("OOPs! Wards is not an array");
}