I am trying to follow the guide here: https://firebase.google.com/docs/cloud-messaging/ios/send-image
I create a new project In Xcode and with my app project open, navigate to File > Add Packages and then I enter https://github.com/firebase/firebase-ios-sdk. After I went to New > Target > Notification Service Extension (embedded this new target into the original target) and pasted in NotificationService.m:
#interface NotificationService ()
#property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
#property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
#end
#implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
// Modify the notification content here...
self.bestAttemptContent.title = [NSString stringWithFormat:#"%# [modified]", self.bestAttemptContent.title];
// Call FIRMessaging extension helper API.
[[FIRMessaging extensionHelper] populateNotificationContent:self.bestAttemptContent
withContentHandler:contentHandler];
self.contentHandler(self.bestAttemptContent);
}
- (void)serviceExtensionTimeWillExpire {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
self.contentHandler(self.bestAttemptContent);
}
#end
I am now getting Use of undeclared identifier 'FIRMessaging' in NotificationService.m.
What did I forget?
In Podfile, use code for pod file
platform :ios, '11.0'
def same_pods
pod 'Firebase/Messaging'
end
target 'Project' do
use_frameworks!
pod 'Firebase', "~> 7.0"
target 'NotificationServiceExt' do
inherit! :search_paths
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0'
config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64 i386"
end
end
installer.generated_projects.each do |project|
project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
end
end
end
end
end
Install the pod file and, in NotificationService file
#import "NotificationService.h"
#import Firebase;
#interface NotificationService ()
#property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
#property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
#end
#implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
// Modify the notification content here as you wish
self.bestAttemptContent.title = [NSString stringWithFormat:#"%#",
self.bestAttemptContent.title];
// Call FIRMessaging extension helper API.
[[FIRMessaging extensionHelper] populateNotificationContent:self.bestAttemptContent withContentHandler:contentHandler];
}
- (void)serviceExtensionTimeWillExpire {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
self.contentHandler(self.bestAttemptContent);
}
#end
Related
I'm using Expressplay SDK for playing DRM contents. I have linked the Expressplay.framework to my iOS project. But while building its giving linking error
Below .h and .mm files
iosdrm.h file
#import <ExpressPlay/ExpressPlay.h>
// import RCTBridgeModule
#import <UIKit/UIKit.h>
#if __has_include(<React/RCTBridgeModule.h>)
#import <React/RCTBridgeModule.h>
#elif __has_include(“RCTBridgeModule.h”)
#import “RCTBridgeModule.h”
#else
#import “React/RCTBridgeModule.h” // Required when used as a Pod in a Swift project
#endif
#define EXP_INIT_ASYNC 1
typedef enum {
DRMCommandStatus_NO_RESULT = 0,
DRMCommandStatus_OK,
DRMCommandStatus_CLASS_NOT_FOUND_EXCEPTION,
DRMCommandStatus_ILLEGAL_ACCESS_EXCEPTION,
DRMCommandStatus_INSTANTIATION_EXCEPTION,
DRMCommandStatus_MALFORMED_URL_EXCEPTION,
DRMCommandStatus_IO_EXCEPTION,
DRMCommandStatus_INVALID_ACTION,
DRMCommandStatus_JSON_EXCEPTION,
DRMCommandStatus_ERROR
} DRMCommandStatus;
#interface iosdrm : NSObject <RCTBridgeModule>
{
UIAlertView* alertView;
NSMutableData *receivedData;
long responseCode;
NSMutableArray* proxies;
NSDictionary * cdvCommand;
}
// #property(nonatomic, readonly) WSB_PlaylistProxy* proxy;
#end
#pragma mark - Private methods
WSB_Result EXP_Initialize(void (^callback)(WSB_Result initialization_result))
{
// initialize the Wasabi runtime
WSB_Result result = WSB_Runtime_Initialize();
if (result != WSB_SUCCESS) {
NSLog(#"Failed to initialize Wasabi Runtime: %d", result);
return result;
}
// check if we're already personalized, without blocking
if (WSB_Runtime_IsPersonalized()) return WSB_SUCCESS;
// personalize in a separate thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// personalize and block until we're done
WSB_Result result = WSB_Runtime_Personalize(nil, 0);
NSLog(#"Wasabi Personalization result: %d", result);
dispatch_async(dispatch_get_main_queue(), ^{ callback(result); });
});
return EXP_INIT_ASYNC;
}
The
iosdrmManager.mm
#import "iosdrm.h"
#import <Foundation/Foundation.h>
#import <React/RCTLog.h>
// import RCTBridge
#import <React/RCTUtils.h>
#if __has_include(<React/RCTBridge.h>)
#import <React/RCTBridge.h>
#elif __has_include(“RCTBridge.h”)
#import "RCTBridge.h"
#else
#import "React/RCTBridge.h" // Required when used as a Pod in a Swift project
#endif
// import RCTEventDispatcher
#if __has_include(<React/RCTEventDispatcher.h>)
#import <React/RCTEventDispatcher.h>
#elif __has_include(“RCTEventDispatcher.h”)
#import "RCTEventDispatcher.h"
#else
#import "React/RCTEventDispatcher.h" // Required when used as a Pod in a Swift project
#endif
struct Node
{
WSB_PlaylistProxy* proxy;
};
static void EXP_OnPlaylistProxyEvent(void* instance, const WSB_PlaylistProxy_Event* event)
{
// instance not used in this example
switch (event->type) {
case WSB_PPET_ERROR_NOTIFICATION:
WSB_PlaylistProxy_ErrorNotificationEvent* e;
e = (WSB_PlaylistProxy_ErrorNotificationEvent*)event;
NSLog(#"Error notification from Playlist Proxy: %d, %s",
e->result, e->error_string);
break;
default:
break;
}
}
static dispatch_queue_t RCTGetMethodQueueDRM()
{
// We want all instances to share the same queue since they will be reading/writing the same database.
static dispatch_queue_t queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
queue = dispatch_queue_create("drmQueue", DISPATCH_QUEUE_SERIAL);
});
return queue;
}
#implementation iosdrm
#synthesize bridge = _bridge;
// Export a native module
// https://facebook.github.io/react-native/docs/native-modules-ios.html
RCT_EXPORT_MODULE(lstdrm);
- (dispatch_queue_t)methodQueue
{
return RCTGetMethodQueueDRM();
}
// Export constants
// https://facebook.github.io/react-native/releases/next/docs/native-modules-ios.html#exporting-constants
- (NSDictionary *)constantsToExport
{
return #{
#"EXAMPLE": #"example"
};
}
// Return the native view that represents your React component
- (UIView *)view
{
return [[UIView alloc] init];
}
#pragma mark - Private methods
WSB_Result EXP_Initialize(void (^callback)(WSB_Result initialization_result))
{
// initialize the Wasabi runtime
WSB_Result result = WSB_Runtime_Initialize();
if (result != WSB_SUCCESS) {
NSLog(#"Failed to initialize Wasabi Runtime: %d", result);
return result;
}
// check if we're already personalized, without blocking
if (WSB_Runtime_IsPersonalized()) return WSB_SUCCESS;
// personalize in a separate thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// personalize and block until we're done
WSB_Result result = WSB_Runtime_Personalize(nil, 0);
NSLog(#"Wasabi Personalization result: %d", result);
dispatch_async(dispatch_get_main_queue(), ^{ callback(result); });
});
return EXP_INIT_ASYNC;
}
while building i'm getting the following error
Undefined symbols for architecture x86_64:
"_WSB_Runtime_Initialize", referenced from:
EXP_Initialize(void (int) block_pointer) in iosdrmManager.o
"_WSB_Runtime_IsPersonalized", referenced from:
EXP_Initialize(void (int) block_pointer) in iosdrmManager.o
"_WSB_Runtime_Personalize", referenced from:
____Z14EXP_InitializeU13block_pointerFviE_block_invoke in iosdrmManager.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Undefined symbols for architecture x86_64:
Seems to suggest you are building for the emulator, instead of for an actual device. The library will likely not work on the emulator (neither does FairPlay, or any other DRM library that i know of). Make sure you are building for an actual iOS device (which should have some variant of arm architecture).
I have a class with an object incall. I have a method that sets it and another methods that runs a method available for that object.
Here is my header file:
#interface RCTPlivo : NSObject <PlivoEndpointDelegate, CXProviderDelegate>
#property (nonatomic) PlivoIncoming *incall;
#property (nonatomic) PlivoEndpoint *endpoint;
#end
And here is my implementation file:
#implementation RCTPlivo
- (void)login {
endpoint = [[PlivoEndpoint alloc] init];
[endpoint login:plivoUser AndPassword:plivoPass];
endpoint.delegate = self;
}
- (void)triggerIncomingCall {
...
CXProvider *callkitProvider = [[CXProvider alloc] initWithConfiguration: configuration];
[callkitProvider setDelegate:self queue:nil];
...
[callkitProvider reportNewIncomingCallWithUUID:currentCall update:update completion:^(NSError * _Nullable error) {
if (error) {
NSLog(#"Error: %#", error);
}
}];
}
- (void)onIncomingCall:(PlivoIncoming *)incoming {
// setting
self.incall = incoming
}
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action
{
// Here self.incall is null
[self.incall answer];
}
#end
When i log self.incall in perfromAnswerCall delegate it's null. When I log it in the onIncomingCall delegate the variable is set.
What am I missing here?
Update
Added the code that initializes the delegates and removed ivars.
Your interface should be:
#interface RCTPlivo : NSObject <PlivoEndpointDelegate>
#property (nonatomic, strong) PlivoIncoming *incall;
#end
and your implementation should be:
#implementation RCTPlivo
- (void)onIncomingCall:(PlivoIncoming *)incoming {
self.incall = incoming;
}
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action {
[self.incall answer];
}
#end
One way this can happen is that you somehow have two separate instances of RCTPlivo. Try stopping the debugger in each of those calls and in the debugger do:
(lldb) po self
If everything's ok then the addresses should be the same.
The infall property is not defined as strong. So we can assume that there is no strong reference to the original object outside this method and it was released.
Update
This property was mentioned as delegate so its weak nature can be a designated behaviour and if this is an option the message sender should have a strong property holding the object reference.
I have created a Cordova App and created iOS platform. I have a requirement to create an Objective-C method in Xcode and invoke it from JavaScript/HTML page.
The code in AppDelegate.h is
#import <Cordova/CDVViewController.h>
#import <Cordova/CDVAppDelegate.h>
#interface AppDelegate : CDVAppDelegate {}
#end
The code in AppDelegate.m is
#import "AppDelegate.h"
#import "MainViewController.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
self.viewController = [[MainViewController alloc] init];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
#end
Any step-by-step tutorial or example?
In Cordova, a native function that can be called from JavaScript is made using a plugin. Take a look at the Plugin Development Guide to create your own plugin or search for already existing plugins that implement the functionality that you need.
This sample is extracted from the iOS Plugin Development Guide:
1. Declare javascript function
window.echo = function(str, callback) {
cordova.exec(callback, function(err) {
callback('Nothing to echo.');
}, "Echo", "echo", [str]);
};
2. Implement platform specific code:
/********* Echo.h Cordova Plugin Header *******/
#import
#interface Echo : CDVPlugin
- (void)echo:(CDVInvokedUrlCommand*)command;
#end
/********* Echo.m Cordova Plugin Implementation *******/
#import "Echo.h"
#import
#implementation Echo
- (void)echo:(CDVInvokedUrlCommand*)command
{
CDVPluginResult* pluginResult = nil;
NSString* echo = [command.arguments objectAtIndex:0];
if (echo != nil && [echo length] > 0) {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:echo];
} else {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
}
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
#end
3. Create plugin config file:
<platform name="ios">
<config-file target="config.xml" parent="/*">
<feature name="Echo">
<param name="ios-package" value="Echo" />
</feature>
</config-file>
</platform>
4. Call this function from Javascript:
window.echo("echome", function(echoValue) {
alert(echoValue == "echome"); // should alert true.
});
I am using AWS Mobile for iOS and I would like to request additional permissions from the Facebook Login (such as user_birthday and other Facebook permissions).
On the Android package you can download from the AWS Mobile HUB it's as simple as modifying the FacebookSignInProvider.java class that is included with the Android package and modify the Facebook loginWithReadPermissions function as such:
LoginManager.getInstance().logInWithReadPermissions(signInActivity,
Arrays.asList("public_profile", "email", "user_birthday"));
But I am also using the iOS Obj-C source package you obtain by building with the AWS Mobile HUB, and only the header files are provided, so it is not possible to modify such implementation.
Any tips?
Regards.
If you downloaded the project from AWS MobileHub, include the AWSMobileHubHelper Framework and AWSMobileClient.swift
AWSFacebookSignInProvider.sharedInstance().setPermissions(["public_profile"]);
I ended up solving this issue by overwriting the AWSFacebookSignInProvider class, so I ended up with a header and implementation files as such:
AWSFacebookSignInProviderCustom.h
#import <Foundation/Foundation.h>
#import <AWSMobileHubHelper/AWSSignInProvider.h>
#import <AWSMobileHubHelper/AWSFacebookSignInProvider.h>
#interface AWSFacebookSignInProviderCustom : AWSFacebookSignInProvider <AWSSignInProvider>
+ (instancetype)sharedInstance;
#end
And then AWSFacebookSignInProviderCustom.m
#import "AWSFacebookSignInProviderCustom.h"
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <FBSDKLoginKit/FBSDKLoginKit.h>
#interface AWSFacebookSignInProviderCustom()
#property (strong, nonatomic) FBSDKLoginManager *facebookLogin;
#end
#implementation AWSFacebookSignInProviderCustom
+ (instancetype)sharedInstance {
static AWSFacebookSignInProviderCustom *_sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedInstance = [AWSFacebookSignInProviderCustom new];
});
return _sharedInstance;
}
- (void)login
{
if (!self.facebookLogin)
self.facebookLogin = [FBSDKLoginManager new];
[self.facebookLogin logInWithReadPermissions:#[#"public_profile", #"email", #"user_birthday"]
handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
if (error) {
NSLog(#"Error!");
} else if (result.isCancelled)
{
// Login canceled, do nothing
NSLog(#"Cancelled!");
} else {
NSLog(#"FSBKDAccess Token: %#", [FBSDKAccessToken currentAccessToken]);
[[AWSFacebookSignInProvider sharedInstance] login];
}
}];
}
#end
So basically that overrides the login button permissions adding any custom permissions you might want. Afterwards, it just calls the standard AWSFacebookSignInProvider login method to complete things as usual.
On your Login Controller, for the handleFacebookLogin method, just use this AWSFacebookSignInProviderCustom class.
That did the trick for me. I hope it can help other people out. :)
I cannot for the life of me get an event to properly send from iOS native across the bridge to the react native JS context. On the Objective-C side I want to have a module to easily send events across the bridge. I have called this class EventEmitter and its definition is as follows:
// EventEmitter.h
#import "RCTBridge.h"
#import "RCTEventDispatcher.h"
#interface EventEmitter : NSObject<RCTBridgeModule>
- (void)emitEvent:(NSString *) eventName withData:(id) eventData;
#end
and the implementation:
// EventEmitter.m
#import "EventEmitter.h"
#implementation EventEmitter
RCT_EXPORT_MODULE();
#synthesize bridge = _bridge;
- (void)emitEvent:(NSString *) eventName withData:(id) eventData
{
NSLog( #"emitting %# with data %#", eventName, [eventData description] );
[[_bridge eventDispatcher] sendDeviceEventWithName:eventName body:eventData];
[[_bridge eventDispatcher] sendAppEventWithName:eventName body:eventData];
}
#end
I'm using both sendDeviceEvent and sendAppEvent because I can't get either to work.
On the JS side of things I register to receive these events in the global namespace of one of my modules (so that I know the event subscription will happen before the event is emitted). I register like this:
console.log( 'ADDING EVENT LISTENERS' );
NativeAppEventEmitter.addListener( 'blah', test => console.log( 'TEST1', test ) );
DeviceEventEmitter.addListener( 'blah', test => console.log( 'TEST2', test ) );
In my log statements I get the following:
2016-03-19 12:26:42.501 [trace][tid:com.facebook.React.JavaScript] ADDING EVENT LISTENERS
2016-03-19 12:26:43.613 [name redacted][348:38737] emitting blah with data [data redacted]
So I can tell that I am sending both an app event and a device event with the tag blah and I have registered to listen for the blah event with both the DeviceEventEmitter and NativeAppEventEmitters but I'm not getting called back in the listeners.
What am I doing wrong?? Thanks for reading!
You can using NativeEventEmitter
// register eventEmitter
const {NGListener} = NativeModules; // NSListener is my class
this.eventEmitter = new NativeEventEmitter(NativeModules.NGListener);
this.eventEmitter.addListener('CancelEvent', (data) => {
console.log(data);
})
In ObjectiveC , you can create
#import <RCTViewManager.h>
#import <RCTEventEmitter.h>
#interface NGListener: RCTEventEmitter <RCTBridgeModule>
#end
#implementation NGListener
RCT_EXPORT_MODULE();
- (NSArray<NSString*> *)supportedEvents {
return #[#"CancelEvent", #"OKEvent"];
}
// And you sent event you want from objectC to react-native
[self sendEventWithName:#"CancelEvent" body:#"Tap`enter code here` on Cancel button from Objc"];
I wrote sample example to handle event from react-native to objectivec and opposite.
https://github.com/lengocgiang/event-listener
Hope this help!!
I've tried dispatching events and it seems bridge is not initialised when you create new EventEmitter instances manually by using [EventEmitter alloc] init]
You should let react-native create instances. I checked native components and they're using -(void)setBridge:(RCTBridge *)bridge method to do initialisation work. Please check out RCTLinkingManager to see an example. It's using NSNotificationCenter to handle events.
// registering for RCTOpenURLNotification evet when the module is initialised with a bridge
- (void)setBridge:(RCTBridge *)bridge
{
_bridge = bridge;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleOpenURLNotification:)
name:RCTOpenURLNotification
object:nil];
}
// emitting openURL event to javascript
- (void)handleOpenURLNotification:(NSNotification *)notification
{
[_bridge.eventDispatcher sendDeviceEventWithName:#"openURL"
body:notification.userInfo];
}
// creating RCTOpenURLNotification event to invoke handleOpenURLNotification method
+ (BOOL)application:(UIApplication *)application
openURL:(NSURL *)URL
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
NSDictionary<NSString *, id> *payload = #{#"url": URL.absoluteString};
[[NSNotificationCenter defaultCenter] postNotificationName:RCTOpenURLNotification
object:self
userInfo:payload];
return YES;
}
In my case I got this working by keeping a value of the bridge from RCTRootView and passing it to the Emitter Instance.
#implementation AppDelegate {
RCTBridge *rootBridge;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *jsCodeLocation;
......
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:#"MyApp"
initialProperties:nil
launchOptions:launchOptions];
rootBridge = rootView.bridge;
.......
}
- (IBAction)doAction:(id)sender {
BridgeEvents *events = [[BridgeEvents alloc] init];
[events setBridge:rootBridge];
[events doMyAction];
}
In my Emitter Class:
#import "RCTEventEmitter.h"
#interface BridgeEvents : RCTEventEmitter <RCTBridgeModule>
- (void)doMyAction;
#end
#import "BridgeEvents.h"
#implementation BridgeEvents
RCT_EXPORT_MODULE();
- (NSArray<NSString *> *)supportedEvents {
return #[#"onEvent"];
}
- (void)doMyAction {
[self sendEventWithName:#"onEvent" body:#""];
}
#end
RNNotification *notification = [RNNotification allocWithZone: nil];
[notification sendNotificationToReactNative]I tried everything above and was not able to get it work in my app.
Finally this worked for me.
#import "RNNotification.h"
#implementation RNNotification
RCT_EXPORT_MODULE();
+ (id)allocWithZone:(NSZone *)zone {
static RNNotification *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super allocWithZone:zone];
});
return sharedInstance;
}
- (NSArray<NSString *> *)supportedEvents
{
return #[#"EventReminder"];
}
- (void)sendNotificationToReactNative
{
[self sendEventWithName:#"EventReminder" body:#{#"name": #"name"}];
}
and while initing the function
RNNotification *notification = [RNNotification allocWithZone: nil];
[notification sendNotificationToReactNative]
You have to use your emitter class like this
[[self.bridge moduleForClass:[RNNotification class]] sendNotificationToReactNative];
You can try following solution to to send event from iOS to React Native
RNEventEmitter.m
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#interface RCT_EXTERN_MODULE(RNEventEmitter, RCTEventEmitter)
RCT_EXTERN_METHOD(supportedEvents)
#end
RNEventEmitter.swift
import Foundation
#objc(RNEventEmitter)
open class RNEventEmitter: RCTEventEmitter {
public static var emitter: RCTEventEmitter!
override init() {
super.init()
RNEventEmitter.emitter = self
}
open override func supportedEvents() -> [String] {
["onReady", "onPending", "onFailure"] // etc.
}
}
Your file from where you are going to emit event add below line
RNEventEmitter.emitter.sendEvent(withName: "onReady", body: [["status":"Connected","data":["name":dev?.name,"deviceId":dev?.identifier]]]);
React Native file
const emitter = new NativeEventEmitter(NativeModules.RNEventEmitter)
In your Bridgin-Header file import
#import <React/RCTEventEmitter.h>
In your useEffect
emitter.addListener('onReady', (data: any) => {
console.log("addListener", data);
Alert.alert(JSON.stringify(data))
});