How can I receive Messages in voip? I can get the Voip Token!
I'm writing in Objective C:
I have searched around the internet but can't find any solutions! All I found is Swift, but can't get the token in Swift. In Objective C I can get token but not get Messages from a line.
apn push "<Token>" -c backgroundfetch.pem -m "Hello"
How can I popup a Messages in Objective C? Here is my code:
#import "AppDelegate.h"
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import PushKit;
#import UserNotifications;
#interface AppDelegate ()
#end
#implementation AppDelegate
NSString *fcmToken = #"";
// Trigger VoIP registration on launch
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self voipRegistration];
return YES;
}
// Register for VoIP notifications
- (void) voipRegistration {
dispatch_queue_t mainQueue = dispatch_get_main_queue();
// Create a push registry object
PKPushRegistry * voipRegistry = [[PKPushRegistry alloc] initWithQueue: mainQueue];
// Set the registry's delegate to self
voipRegistry.delegate = self;
// Set the push type to VoIP
voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
}
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type{
if([credentials.token length] == 0) {
NSLog(#"voip token NULL");
return;
}
NSLog(#"PushCredentials: %#", credentials.token);
}
// Handle incoming pushes
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type {
// Process the received push
NSLog(#"Get");
}
#end
My info.plist:
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
<string>audio</string>
<string>fetch</string>
<string>remote-notification</string>
</array>
In your case the solution is to send a silent push notification. Once the silent push notification arrives, execute your code with background task.
Here is the good explanations for sending a silent push notification.
https://stackoverflow.com/a/36327058/9106403
Related
I am quite new to react native and and the bridging mechanism with native code, especially when the framework has delegates. Assume I am trying to bridge the following framework:
#protocol BRPtouchNetworkDelegate;
#class PLNetworkModule;
#interface BRPtouchNetworkManager : NSObject <NSNetServiceBrowserDelegate,NSNetServiceDelegate>
#property(retain, nonatomic) NSMutableArray* registeredPrinterNames;
#property(assign, nonatomic) BOOL isEnableIPv6Search;
- (int)startSearch: (int)searchTime;
- (NSArray*)getPrinterNetInfo;
- (BOOL)setPrinterNames:(NSArray*)strPrinterNames;
- (BOOL)setPrinterName:(NSString*)strPrinterName;
- (id)initWithPrinterNames:(NSArray*)strPrinterNames;
- (id)initWithPrinterName:(NSString*)strPrinterName;
#property (nonatomic, assign) id <BRPtouchNetworkDelegate> delegate;
#end
#protocol BRPtouchNetworkDelegate <NSObject>
-(void) didFinishSearch:(id)sender;
#end
The following is the bridge module I implemented:
RCTBRPtouchNetworkManager.h
#import <React/RCTBridgeModule.h>
#import <BRPtouchPrinterKit/BRPtouchPrinterKit.h>
#interface RCTBRPtouchNetworkManager : NSObject <RCTBridgeModule, BRPtouchNetworkDelegate>
#end
RCTBRPtouchNetworkManager.m
#import "RCTBRPtouchNetworkManager.h"
#import <BRPtouchPrinterKit/BRPtouchPrinterKit.h>
#import <React/RCTLog.h>
#implementation RCTBRPtouchNetworkManager {
BRPtouchNetworkManager *_networkManager;
}
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
{
RCTLogInfo(#"Pretending to create an event %# at %#", name, location); //a dummy method to test the bridge
}
RCT_EXPORT_METHOD(startSearchWithTimeout:(int)time) {
RCTLogInfo(#"Bridge started search with time %d", time);
_networkManager = [[BRPtouchNetworkManager alloc] init];
_networkManager.delegate = self; //I'm setting delegate here
_networkManager.isEnableIPv6Search = NO;
NSString * path = [[NSBundle mainBundle] pathForResource:#"PrinterList" ofType:#"plist"];
if( path )
{
NSDictionary *printerDict = [NSDictionary dictionaryWithContentsOfFile:path];
NSArray *printerList = [[NSArray alloc] initWithArray:printerDict.allKeys];
[_networkManager setPrinterNames:printerList];
} else {
RCTLogInfo(#"PrinterList path not found");
}
// Start printer search
[_networkManager startSearch: 5.0];
}
- (void)didFinishSearch:(id)sender {
NSLog(#"didFinishedSearch"); //this delegate method is not called
}
#end
I can easily call the dummy method and see the results in the logs. However, the delegate method didFinishSearch() is never called. I call this from javascript as follows:
componentDidMount() {
let networkManager = NativeModules.BRPtouchNetworkManager;
networkManager.startSearchWithTimeout(5.0);
}
I there something I am missing? Am I implementing delegate properly? Is this kind of functionality even possible (can't seem to not since the delegate method was used by iOS community for a long time). Your help is much appreciated.
EDIT
I found that adding the following to my bridge manager file made the delegate to fire (thanks to this post)
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
However, even though this solves the problem, I'd like a more technical understanding on what is going on here since I can't seem to exactly grasp it. Thank you
I know this isn’t an an answer to the post but for the bit where you’ve asked for a more technical understanding - dispatch_get_main_queue(); puts the delegate method responses on to the main thread. Since JS is single threaded any process on the background thread won’t be visible to it.
I have an app that sends out the following NSDistributed Notification, parts of which I eventually want to "grab" with a CLI and pipe it to a shell script:
{name = TheApplicationNotification; object = TheApplicationNotification; userInfo = {
path = "/path/to/a/file";
}}
I don't really know anything about programming, but I managed to grab the whole notification with the following code for a small CLI, shamelessly put together from two older stackoverflow comments:
#import <Foundation/NSObject.h>
#import <Foundation/NSNotification.h>
#import <Foundation/NSString.h>
#import <Foundation/NSDistributedNotificationCenter.h>
#import <Foundation/NSRunLoop.h>
#import <stdio.h>
#interface monitorcli: NSObject {}
-(id) init;
-(void) receive: (NSNotification*) notification;
#end
#implementation monitorcli
-(id) init {
NSDistributedNotificationCenter * center
= [NSDistributedNotificationCenter defaultCenter];
[center addObserver: self
selector: #selector(receive:)
name: #"TheApplicationNotification"
object: nil
];
fprintf(stderr,"Listening...\n");
[[NSRunLoop currentRunLoop] run];
fprintf(stderr,"Stopping...\n");
return self;
}
-(void) receive: (NSNotification*) notification {
NSLog(#"%#", notification);
}
#end
int main( int argc, char ** argv) {
[[monitorcli alloc] init];
return 0;
}
I have also managed to just get the notification name by substituting
NSLog(#"%#", notification);
for
fprintf(stderr,"%s\n", [[notification name] UTF8String] );
My question now is: what changes in the code are necessary to only print the "path" key in userInfo?
Try:
NSLog(#"%#", notification.userInfo[#"path"]);
The .userInfo Gets the value of the userInfo property, this value is a dictionary. The [#"path"] then gets the value associated with the #"path" key in the dictionary.
Note: all code typed directly into answer, expect minor typos.
I am trying to create a plugin for Unity using Objective-C for an app running on Mac. I need to get the URL when launching my app from a link using an url protocol. I haven't used Objective-C before, so I am having trouble trying to make it work.
I am using an example provided by Unity (download example) and changing the methods to the ones I need to get the URL, but my app crashes on the line nsApplication = [[NSApplication alloc] init]; on the _GetUrl method. I have no idea what I am missing/doing wrong. Also, _GetUrl is the method called from Unity when I want to ask for the url (which is called at the first frame), but I am afraid it might be called after applicationWillFinishLaunching. So where should I actually set the delegate so that applicationWillFinishLaunching happens after the delegate is set?
I use an .h and a .m script and then compile the bundle and import it into Unity as a plugin. This is my code:
PluginUrlHandler.h
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#interface NSApplicationDelegate : NSObject
{
NSString* urlString;
}
// NSApplication delegate methods
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification;
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
//Other methods
- (NSString *)getUrl;
#end
PluginUrlHandler.m
#import <Foundation/Foundation.h>
#import "PluginUrlHandler.h"
#implementation NSApplicationDelegate
- (id)init
{
self = [super init];
urlString = #"nourl";
return self;
}
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification
{
NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
[appleEventManager setEventHandler:self
andSelector:#selector(handleGetURLEvent:withReplyEvent:)
forEventClass:kInternetEventClass andEventID:kAEGetURL];
}
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
[event paramDescriptorForKeyword:keyDirectObject] ;
NSString *urlStr = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
urlString = urlStr;
}
- (NSString *)getUrl
{
return urlString;
}
#end
static NSApplicationDelegate* delegateObject = nil;
static NSApplication* nsApplication = nil;
// Helper method to create C string copy
char* MakeStringCopy (const char* string)
{
if (string == NULL)
return NULL;
char* res = (char*)malloc(strlen(string) + 1);
strcpy(res, string);
return res;
}
#if c__plusplus
extern "C" {
#endif
const char* _GetUrl ()
{
if (delegateObject == nil)
delegateObject = [[NSApplicationDelegate alloc] init];
if (nsApplication == nil)
nsApplication = [[NSApplication alloc] init];
[nsApplication setDelegate:delegateObject];
return MakeStringCopy([[delegateObject getUrl] UTF8String]);
}
#if c__plusplus
}
#endif
If your application is crashing, you need to provide some information, such as a stack trace or error message so we can best help. I'm assuming the error you're receiving looks like this:
2016-03-06 10:07:14.388 test[5831:230418] *** Assertion failure in -[NSApplication init], /Library/Caches/com.apple.xbs/Sources/AppKit/AppKit-1404.34/AppKit.subproj/NSApplication.m:1980
2016-03-06 10:07:14.391 test[5831:230418] An uncaught exception was raised
2016-03-06 10:07:14.391 test[5831:230418] Creating more than one Application
You shouldn't create your own NSApplication object. Just use the system one by referencing [NSApplication sharedApplication].
Generally speaking, you shouldn't need an NSApplication (or NSApplicationDelegate) for a plugin, though. The program that's loaded you should already have one, and you don't want to mess with that. Just create a custom NSObject subclass to be your AppleEvent handler. You don't need NSApplication (or it's delegate) at all for this. Any object can be the target of an AppleEvent.
You can't use things like applicationDidFinishLaunching:withOptions: from a plugin in any case. It's too late. The application has long since launched. You'll need to add your AppleEvent handler in some function called from Unity. I'm not particularly familiar with Unity's plugin engine, so I don't know if there's a particular "load" function that gets called automatically (I don't see one in the sample code). You may have to call something yourself. It would have to occur after the plugin is loaded, but before the Get URL Apple Event happens (it's unclear what you expect to generate that).
Just curious what you're trying to pull off with this. I've never seen a protocol handler used this way.
Creation of NSApplication instance looks very suspicious. Normally you don't create it as it is a singleton by definition.
So instead of this:
if (nsApplication == nil)
nsApplication = [[NSApplication alloc] init];
you should have rather this (getting current NSApplication instance):
if (nsApplication == nil)
nsApplication = [NSApplication sharedApplication];
I made a tutorial on this, see Override app delegate in Unity for iOS and OSX (4/4) Inject code to Mach-O binary.
It uses code injection to set an Objective-C class to respond the corresponding Apple Event.
In Header file
#import <WatchKit/WatchKit.h>
#import <Foundation/Foundation.h>
#import <WatchConnectivity/WatchConnectivity.h>
#interface InterfaceController : WKInterfaceController<WCSessionDelegate>
- (IBAction)lastSongButtonClick;
- (IBAction)playSongButtonClick;
- (IBAction)nextSongButtonClick;
#property (strong, nonatomic) IBOutlet WKInterfaceLabel *songTitleLabel;
#property (strong, nonatomic) IBOutlet WKInterfaceButton *playSongButton;
#end
So I implemented the WCSessionDelegate and every time I receive about the UI, I would want it to update. So in my .m file I have:
- (void)session:(nonnull WCSession *)session didReceiveMessage:(nonnull NSDictionary<NSString *,id> *)message{
NSString* type = [message objectForKey:#"type"];
if([type isEqualToString:#"UIUpdateInfo"]){
NSLog(#"Watch receives UI update info");
[self handleUIUpdateInfo:[message objectForKey:#"content"]];
}
}
AND
- (void)handleUIUpdateInfo:(NSDictionary*)updateInfo{
[self.songTitleLabel setText:[updateInfo objectForKey:#"nowPlayingSongTitle"]];
[self.playSongButton setBackgroundImage:[updateInfo objectForKey:#"playButtonImage"]];
}
However, it doesn't seems to update. Is there any proper way to update?
You're halfway there. You've configured receiving the message on the watch side correctly, but you'll need to trigger a message to be sent when the UI is updated (therefore triggering didReceiveMessage to execute and update the appropriate content).
Where ever you are making changes to the UI, you'll need to include this:
NSDictionary *message = //dictionary of info you want to send
[[WCSession defaultSession] sendMessage:message
replyHandler:^(NSDictionary *reply) {
//handle reply didReceiveMessage here
}
errorHandler:^(NSError *error) {
//catch any errors here
}
];
Also, make sure you're activating the WCSession properly. This is usually done in viewDidLoad or willAppear depending on whether you're implementing this on the phone or the watch.
- (void)viewDidLoad {
[super viewDidLoad];
if ([WCSession isSupported]) {
WCSession *session = [WCSession defaultSession];
session.delegate = self;
[session activateSession];
}
}
You can see a full example of an end-to-end Watch to iPhone data transfer in this tutorial - http://www.kristinathai.com/watchos-2-tutorial-using-sendmessage-for-instantaneous-data-transfer-watch-connectivity-1
So I got this code inside the update() function/method that tracks the game session in seconds (this is for achievement purposes) If someone has a better way of doing this, I'm all ears:
-(void)update:(NSTimeInterval)currentTime
{
if (pauseTimer == NO)
{
millisecondsTimer++;
if(millisecondsTimer == 60) //Remember that SK runs at 60 FPS default which means 60 equals 1 second.
{
millisecondsTimer = 0; //Reset the counter to 0 to begin again.
_secondsTracker++; //Add 1 second to this property.
}
}
else
{
NSLog(#"Timer paused.");
}
}
I want to take the _secondsTracker & save its value right before someone turns off the game completely (as in double clicks home button & swipes the game window up & away). The way I have it working now is using the appDelegate like so:
AppDelegate.h
#import <UIKit/UIKit.h>
BOOL pauseTimer;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "GameScene.h" //For sessionTracker property.
#import "GameData.h" //To call upon gdTotalSessionTime property.
#interface AppDelegate ()
#end
#implementation AppDelegate
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
/*Override point for customization after application launch.*/
return YES;
}
-(void)applicationWillResignActive:(UIApplication *)application
{
/*Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.*/
/*Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.*/
pauseTimer = YES; //Will stop the secondsTimer accumulating value.
}
-(void)applicationDidEnterBackground:(UIApplication *)application
{
/*Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.*/
/*If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.*/
//Will add secondsTracker value to the total (gdTotalSessionTIme).
GameScene *gS = [[GameScene alloc] init];
[GameData sharedGameData].gdTotalSeconds = [GameData sharedGameData].gdTotalSeconds + [gS.secondsTracker]; //Supposed to add the secondsTracker value to the gdTotalSeconds value.
[[GameData sharedGameData] save]; //This saves all the data to a file in app.
NSLog(#"THIS SESSION TIME: %ld seconds", gS.secondsTracker);
}
-(void)applicationWillEnterForeground:(UIApplication *)application
{
/*Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.*/
}
-(void)applicationDidBecomeActive:(UIApplication *)application
{
/*Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.*/
pauseTimer = NO; //Will resume the secondsTimer value accumulation.
}
-(void)applicationWillTerminate:(UIApplication *)application
{
/*Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.*/
}
The line of code that's giving me problems is this one:
[GameData sharedGameData].gdTotalSeconds = [GameData sharedGameData].gdTotalSeconds + gS.secondsTracker;
More specifically gS.secondsTracker. Xcode keeps wanting to replace it into this:
*([GameData sharedGameData].gdTotalSeconds + gS.secondsTracker);
Doing so, nothing adds up the way I want it too & I know for a fact the GameData class is working correctly & saving other data to a file it created. Someone please tell me what these *() are?
While I advised that you can probably provide a singleton accessor to get hold of the currently running instance of GameScene it's not quite a singleton as you will want to allow GameScene objects to be created as normal. What is required is simply accessing the "current" instance, with something like:
header
#interface GameScene : SKScene
...
+ (GameScene *)currentGameScene;
...
#end
implementation
static GameScene *_instance = nil;
#interface GameScene
- (instancetype)init...
{
if (self) ...
_instance = self;
return self;
}
- (void)dealloc
{
if (self == _instance)
_instance = nil;
}
+ (GameScene *)currentGameScene
{
return _instance;
}