I'm implementing Facebook SDK, it tells me to replace in AppDelegate.m with
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(nonnull NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
But i see i already have the following:
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
which looks the exact same except for the application vs app. What is the difference? Can I safely change "app" to "application"?
I will accept a yes or no answer, but I would also appreciate any explanations.
The keyword labels are part of the selector (application:openURL:Options:), but the parameter names (to the right of the colon) are not. They're just the names internal to the method's implementation.
Related
I am using checkmarx for security vulnerabilities in code. (react-native). I enabled deep linking in react-native using this guide from the official documentation for ios https://reactnative.dev/docs/linking. From the documentation i added this code to AppDelegate.m
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
return [RCTLinkingManager application:application openURL:url options:options];
}
However checkmarx reports that i need to sanitize or validate the url to prevent XSS attacks, any idea on how to achieve this?
To mitigate the XSS vulnerability in the code, you must URL encode the url argument by using the stringByAddingPercentEncodingWithAllowedCharacters method:
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
NSString *urlEncoded = [url stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
return [RCTLinkingManager application:application openURL:urlEncoded options:options];
}
I have started Objective C a few hours ago, apologies if my question is already answered, I could not find anything similar.
I have my API key specified in the AppDelegate as follows:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[GMSServices provideAPIKey = "..."]
}
As per google documentation this key need to be provided when I query for the nearby locations. Ideally, I would like to have my key in one file, no copy-paste.
Is there way to get the reference to the key from AppDelegate and use it in another file? Maybe it should be kept in yet another file and both AppDelegate file and the file that calls Locations API should query that another file? Thanks.
You don't need to reference this key in any other file. The API key is paired with your application's bundle ID to identify it. You should call '+ (BOOL) provideAPIKey:(NSString *)APIKey' exactly once in your application.
Therefore, if you called it in application: didFinishLaunchingWithOptions:, you should be able to use google maps services in any other class.
Take a look at https://developers.google.com/maps/documentation/ios/ if you want to see some example codes.
However, if you want, to any reason, be able to reuse any object between your class, you should use Singleton.
The API key, for example is a NSString. Thus, you would declare a class in your .h file like:
#interface APIKey : NSObject
+ (APIKey*)sharedInstance;
#property NSString * apiValue;
#end
And a .m:
#implementation APIKey
+ (APIKey *)sharedInstance{
static APIKey * sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
#end
Then you would be able to access 'apiValue' in any class (after import .h file) just calling
[[APIKey sharedInstance] apiValue];
Or set new values like this:
[[APIKey sharedInstance] setApiValue:#"someThingHere"];
But, as I said, you don't need this to Google API Key.
Hope this helps.
Though I have linked the sqlite3 framework and included the headers in my application delegate file, Xcode wants to change:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
if ([MyDatabase database]) sqlite3_close([MyDatabase database]);
}
to this:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
if ([MyDatabase database]) sqlite3_close((__bridge sqlite3 *)([MyDatabase database]));
}
In the code above, database is a singleton reference to an instance of MyDatabase that works in all other aspects of the program.
I've made a simple app for mac, however when it laods in content(via JS) it redirects due to adds or something, is there any way to prevent WebView to going to any other URL than the one defined in the code?
Currently trying to stop it with (UPDATED)
webberAppDelegate.h
#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
#interface webberAppDelegate : NSObject <NSApplicationDelegate> {
WebView *webview;
}
#property (assign)IBOutlet WebView *webview;
#end
webberAppDelegate.m
#import "webberAppDelegate.h"
#implementation webberAppDelegate
//#synthesize window;
//#synthesize webber;
#synthesize webview;
- (void)applicationDidFinishLaunching:(NSNotification *)Notification
{
NSURL*url=[NSURL URLWithString:#"http://simplyshows.com/dev/forums/"];
NSURLRequest*request=[NSURLRequest requestWithURL:url];
[[webview mainFrame] loadRequest:request];
webview.resourceLoadDelegate = self;
}
-(NSURLRequest*) webView:(WebView*)webview resource:(id)sender willSendRequest:(NSURLRequest*)request redirectResponse:(NSURLResponse*)redirectresponse fromDataSource:(WebDataSource*)dataSource {
NSLog(#"willSendRequest delegate method called");
}
#end
See here for details on connection:willSendRequest:redirectResponse:
UPDATED: sorry, I breezed right over the fact that this is a Mac app not an iPhone app. Limited experience with the former; however, I believe that the same concepts apply, just instantiated differently.
Looking at the documentation, it looks like you want webView:resource:willSendRequest:redirectResponse:fromDataSource (see here for details). You'll also need to set webberAppDelegate's resourceLoadDelegate to self.
UPDATED: okay, here's a bit more detail on the process. You need to understand a bit about how protocols and delegates work in Objective-C. Read that material in support of what follows.
Protocols function like interfaces in Java or C#, or abstract functions in C++. They are basically a form of contract. They are mandatory by default but can be marked explicitly as #optional, meaning the compiler won't choke if one is omitted. If you look at the documentation for WebResourceLoadDelegate, you'll see that all the methods are optional. We want just one here, the webView:resource:willSendRequest:redirectResponse:fromDataSource method.
The other part of this is the concept of the delegate. Delegates function as callbacks. This involves both an object that will carry out the callback logic and an implementation of the logic (i.e., the implementation of the method from the protocol above). This can be implemented in a number of ways, but Cocoa has a more-or-less standardized way of doing it. You need to provide the implementation of the method, and you need to identify which object is going to carry out the logic. Note that WebView has a bunch of different delegate protocols. Adopting all or part of one of them is called conforming to the protocol. This is stated in code as (I am providing a skeleton of your class here):
#interface webberAppDelegate : NSObject<WebResourceLoadDelegate> {
WebView* webview;
}
#end
here I'm assuming you derive from NSObject; substitute whatever your base class is. This lets the compiler know to expect that you'll provide implementations of the mandatory methods as well as whichever optional methods you require. It will complain if you do not implement the mandatory methods.
The more critical piece is to establish that the Webview ivar has a delegate that is going to provide implementations for one or all of methods declared by WebResourceLoadDelegate. You have a property for this ivar -- webview. Somewhere (e.g., in the viewDidLoad -- that's where I'd do it in iOS) you need to declare:
webview.resourceLoadDelegate = self;
assuming you want the callback handled by webberAppDelegate. Then in webberAppDelegate's implementation you need to provide the definition for the method webView:resource:willSendRequest:redirectResponse:fromDataSource:
-(NSURLRequest*) webView:(WebView*)webview resource:(id)sender willSendRequest:(NSURLRequest*)request redirectResponse:(NSURLResponse*)redirectresponse fromDataSource:(WebDataSource*)dataSource {
NSLog(#"willSendRequest delegate method called");
}
If you implement this much, you should see the log statement echoed in the console when you run your application. It's in that method that you need to handle the redirect. As I said before, I'm not well versed in the implementation of this protocol. According to this thread, it may actually be the WebPolicyDelegate protocol that you want. The principles involved will be the same.
As far as I can say, these two delegate methods can catch URLs for other frames/content. You should try around and test them on your pages. Read the Help for these methods to see how to e.g. prevent the client redirect.
// WebView delegate methods
// Used to indicate that we've started loading (so that we can update our progress indicator
// and status text field)
- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame
{
if( frame == [myWebView mainFrame] )
NSLog(#"EntryController: Started loading mainFrame");
else
NSLog(#"EntryController: Started loading Frame : %#", [[frame.dataSource request] URL]);
}
- (void)webView:(WebView *)sender willPerformClientRedirectToURL:(NSURL *)URL
delay:(NSTimeInterval)seconds fireDate:(NSDate *)date
forFrame:(WebFrame *)frame
{
NSLog(#"EntryController: willPerformClientRedirectToURL: %#",URL);
}
greetings
Jimmy
Although jstevenco's answer explains how you can know if a webview is trying to go to another url, it doesn't answer how you can prevent the webview from going to such url.
If you want to prevent WebView to going to any other URL you must implement the WebPolicyDelegate Protocol. It's important to note that this is an informal protocol so you cannot write #interface MyDelegate : NSObject <WebPolicyDelegate>.
Instead in your webberAppDelegate.h import Webkit:
#import <WebKit/WebPolicyDelegate.h>
and in webberAppDelegate.m implement the method webView:decidePolicyForNavigationAction:request:frame:decisionListener:, this method "is invoked every time a server redirect is encountered unless blocked by an earlier policy decision". (WebPolicyDelegate Protocol Documentation)
In this method you need to tell the decisionListener that it must ignore any redirection. This is the implementation:
- (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation
request:(NSURLRequest *)request
frame:(WebFrame *)frame
decisionListener:(id <WebPolicyDecisionListener>)listener {
[listener ignore];
}
However, beware with this implementation because you will ignore ANY redirect, and I don't think that's what you want (it would be a static webpage); more likely, what you want it's to prevent redirections that leave your domain so probably what you really want is:
- (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation
request:(NSURLRequest *)request
frame:(WebFrame *)frame
decisionListener:(id <WebPolicyDecisionListener>)listener {
if (![[[request URL] absoluteString] hasPrefix:#"yourdomain.com"]) {
[listener ignore];
}
}
Yes you can do this. Implement
– webView:shouldStartLoadWithRequest:navigationType:
This delegate . This method gets called whenever your webview is about to make a request. So now when someone clicks a button on your webpage, you will get a call to this method. After you catch this call, you can choose to do whatever you want with it. Like redirect the link through your own servers, or log a request to your server about user activity etc.
Example - here you are trying to intercept any links clicked on your webpage & pass it through myMethodAction first.
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
if(navigationType == UIWebViewNavigationTypeLinkClicked)
{
if(overrideLinksSwitch.on == TRUE)
{
[self myMethodAction];
[myWebView stopLoading];
return YES;
}
else
{
return YES;
}
}
return YES;
}
Hope this helps...
while creating a library that will be used on several projects, I encountered an error that I was not able to resolve by myself.
The library is composed of several "modules" that each declares its set of classes. The modules declares a header file that references the classes. Each module header is included in the library header, and all of them are copied to the library target.
The "GMData" module defines the ORM layer of the library, it declares a "GMInitializerBase" class, its purpose is to initialize the module. It must be called once in the UIApplicationDelegate.
The "GMModel" module contains the base model for the application (Categories, Articles, ...), It must register itself to "GMData" in order to function properly.
Structure:
<Library Root>
Library.h
<GMData>
GMData.h
GMInitializerBase.{h,m}
<GMModel>
GMModel.h
GMInitializerBase+GMModel.{h,m}
Contents of Library.h
#import "GMData.h"
#import "GMModel.h"
Contents of GMData.h
#import "... ORM related headers ..."
#import "GMInitializerBase.h"
Contents of GMInitializerBase.{h,m}
#import "... ORM Classes ..."
#interface GMInitializerBase : NSObject {
}
+ (void) bootstrap;
+ (GMInitializerBase*) initializer; // autoreleased instance creator
- (void) setup;
- (void) setupStore:(GMManagerFactory*)factory; // Setup database connection
- (void) setupHelpers:(GMHelperFactory*)factory; // Register helpers (abstract)
- (void) setupManagers:(GMManagerFactory*)factory; // Register managers (abstract)
#end
#implementation GMInitializerBase
+ (void) bootstrap {
GMInitializerBase* initializer = [self initializer];
[initializer setup];
}
- (void) setup {
/* Breakpoint 01 */
GMHelperFactory* helperFactory = [GMHelperFactory sharedInstance];
GMManagerFactory* managerFactory = [GMManagerFactory sharedInstance];
[self setupStore:managerFactory];
[self setupHelpers:helperFactory];
[self setupManagers:managerFactory];
}
#end
Contents of GMModel.h
#import "... Base Models files ..."
#import "GMInitializerBase+GMModel.h"
Contents of GMInitializerBase+GMModel.{h,m}
#interface GMInitializerBase (GMModel_Additions)
- (void) setup;
- (void) setupGMModelHelpers:(GMHelperFactory*)factory;
- (void) setupGMModelManagers:(GMManagerFactory*)factory;
#end
#implementation GMInitializerBase (GMModel_Additions)
- (void) setup {
/* Breakpoint 02 */
GMHelperFactory* helperFactory = [GMHelperFactory sharedInstance];
GMManagerFactory* managerFactory = [GMManagerFactory sharedInstance];
// parent implementation
[self setupStore:managerFactory];
// current implementation
[self setupGMModelHelpers:helperFactory];
[self setupGMModelManagers:managerFactory];
// parent implementation
[self setupHelpers:helperFactory];
[self setupManagers:managerFactory];
}
- (void) setupGMModelHelpers:(GMHelperFactory*)factory { /* ... */ }
- (void) setupGMModelManagers:(GMManagerFactory*)factory { /* ... */ }
#end
Contents of ProjectAppDelegate.m (located in another project, it includes the library.a and search the "Headers" directory)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[GMInitializerBase initializer] setup];
}
Stops at the first breakpoint (Breakpoint 01)
It crashed when in the library:
I declare an addition without overloading a method;
I declare an addition to a Cocoa class ([NSString toto]) without overloading;
In works when in the test project:
I declare an addition to a Cocoa class ([NSString toto]) without overloading;
I didn't try to overload a library class but I assume it will work too.
My problem is the following: I can't get the addition workingm and I need it.
Thanks for reading, thanks for answering.
Make sure you have the -all_load and -ObjC flags set in the "Other Linker Flags" in the project settings. Categories in a library won't work without them.
In Objective-C, you shouldn't override the method in a category of a class. Say you have
#implementation MyClass
-(void)foo
{
NSLog(#"%#",#"original!");
}
#end
and later you have
#implementation MyClass (MyCategoryA)
-(void)foo
{
NSLog(#"%#",#"categoryA!");
}
#end
#implementation MyClass (MyCategoryB)
-(void)foo
{
NSLog(#"%#",#"categoryB!");
}
#end
Then the result of
MyClass* myInstance=...;
[myInstance foo];
is not reliable, see the discussion in the official documentation. The documentation says it works if you have only one category, but the documentation says at the same time you shouldn't use that feature. So, don't do this.
The sole exception is +load. If a category defines this method, the runtime calls it for each category you define. So, if you want to perform some initialization task per category, +load is the way. Read the official documentation and this blog post by Mike Ash.