I had created network manager by using the below code. but as soon the first line of call is run the manager is being nil so any other methods are getting not effected. Can Anyone let me know that what wrong thing I had done ?
NEVPNManager *manager = [NEVPNManager sharedManager];
NEVPNProtocolIPSec *p = [[NEVPNProtocolIPSec alloc] init];
p.username = #"MYUSERNAME";
p.passwordReference = [#"MYPW" dataUsingEncoding:NSUTF8StringEncoding];
p.serverAddress = #"[NetworkIP]";
p.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret;
p.sharedSecretReference = [#"SharedSecretHashCode" dataUsingEncoding:NSUTF8StringEncoding];
[manager setProtocol:p];
[manager setOnDemandEnabled:NO];
[manager setLocalizedDescription:#"VIT VPN"];
NSArray *array = [NSArray new];
[manager setOnDemandRules: array];
NSLog(#"Connection desciption: %#", manager.localizedDescription);
NSLog(#"VPN status: %li", (long)manager.connection.status);
[manager saveToPreferencesWithCompletionHandler:^(NSError *error) {
if(error) {
NSLog(#"Save error: %#", error);
}
}];
"manager" is being nil . please help. thanks in advance.
I found Solution for my question for the NEVPNManager instances.
When using this to the app developer must need its related certificates in which The APPID has has enabled the VPN Configuration & controls. and this app must need to run in the device.
So the NEVPNManager will not be nil and it can be adapt from the shared instance of the device. (also this is from NetworkExtension.framework which is available for iOS8 & higher devices)
May be this can help anyone who is having the same issue.
Related
I Face a big problem,I made a VPN for IOS Devices,it is on the appstore,it is working nicely,However i face problem with macos application,I use same codes.Same codes work for IOS Devices however they dont work for MacOS application.
The Problem says ;
No VPN shared secret was provided. Verify your settings and try reconnecting.
When i try to connect to vpn.
Code that i use for connect vpn
[[NEVPNManager sharedManager] loadFromPreferencesWithCompletionHandler: ^(NSError *error) {
NEVPNProtocolIPSec *p = [[NEVPNProtocolIPSec alloc] init];
p.serverAddress =ipAddress;
p.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret;
NSLog(#"vpn connecting to ip %#",ipAddress);
p.username=#"vpnuser";
p.sharedSecretReference = [KeyChainHelper load:sharedSecret];
p.passwordReference = [KeyChainHelper load:password];
// NSData * data = [self searchKeychainCopyMatching:sharedSecret];
p.disconnectOnSleep = NO;
[NEVPNManager sharedManager].protocolConfiguration=p;
NSMutableArray *rules = [[NSMutableArray alloc] init];
NEOnDemandRuleConnect *connectRule = [NEOnDemandRuleConnect new];
[rules addObject:connectRule];
[[NEVPNManager sharedManager] setOnDemandRules:rules];
[[NEVPNManager sharedManager] setLocalizedDescription:#"VPN Fire"];
[[NEVPNManager sharedManager] setEnabled:YES];
[[NEVPNManager sharedManager] saveToPreferencesWithCompletionHandler: ^(NSError *error) {
NSLog(#"Save VPN to preference complete");
if (error) {
NSLog(#"Save error: %#", error);
}
NSError *startError;
[[NEVPNManager sharedManager].connection startVPNTunnelAndReturnError:&startError];
delayStart(5)
NSLog(#"%#",[NEVPNManager sharedManager]);
NSLog(#"%#",[NEVPNManager sharedManager]);
delayEnd
if(startError) {
NSLog(#"Start error: %#", startError.localizedDescription);
}
}];
}];
Here i put some screenshoots;
Looks like KeyChainHelper is a wrapper for accessing the keychain. It isn't clear exactly what the KeyChainHelper::load() method returns, but my guess is either a standard reference or data.
NEVPNProtocolIPSec::sharedSecretReference is defined as:
A persistent keychain reference to a keychain item containing the IKE shared secret.
You need to create a keychain item of type kSecClassGenericPassword to use as the shared secret, and provide a persistent reference to the keychain item. A persistent reference is critical here, as it can be stored to disk or passed between processes, which is required for NEVPNManager to access the shared secret and connect your VPN. Likewise for passwordReference.
You will need to use SecItemCopyMatching with return type kSecReturnPersistentRef to achieve this. Your KeyChainHelper class may provide a method to return the persistent reference.
I want to establish a VPN connection with my VPN server.
I installed VPN server from digital oceans.
I want to make VPN application for IOS by using objective-C by using my VPN connection settings.
Here I faced problem:
no VPN shared secret was provided.
Here I Used Codes
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[[NEVPNManager sharedManager] setEnabled:YES];
[[NEVPNManager sharedManager] loadFromPreferencesWithCompletionHandler: ^(NSError *error) {
NEVPNProtocolIPSec *p = [[NEVPNProtocolIPSec alloc] init];
p.serverAddress =#"178.62.78.101";
p.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret;
p.useExtendedAuthentication = YES;
NSString *secret = #"gfJL$$";
NSData *secretData = [secret dataUsingEncoding:NSUTF8StringEncoding];
p.sharedSecretReference=secretData;
p.localIdentifier=#"londra1";
p.username=#"root";
p.passwordReference=[[SSKeychain passwordForService:#"2eee9fa59" account:#"2eee9fa5"] dataUsingEncoding:NSUTF8StringEncoding];
p.disconnectOnSleep = NO;
[NEVPNManager sharedManager].protocolConfiguration=p;
NSMutableArray *rules = [[NSMutableArray alloc] init];
NEOnDemandRuleConnect *connectRule = [NEOnDemandRuleConnect new];
[rules addObject:connectRule];
[[NEVPNManager sharedManager] setOnDemandRules:rules];
[[NEVPNManager sharedManager] setLocalizedDescription:#"vpn"];
[[NEVPNManager sharedManager] setEnabled:YES];
[[NEVPNManager sharedManager] saveToPreferencesWithCompletionHandler: ^(NSError *error) {
NSLog(#"Save VPN to preference complete");
if (error) {
NSLog(#"Save error: %#", error);
}
}];
NSError *startError;
[[NEVPNManager sharedManager].connection startVPNTunnelAndReturnError:&startError];
if(startError) {
NSLog(#"Start error: %#", startError.localizedDescription);
}
}];
return YES;
}
You are setting sharedSecretReference as an NSData, but this conflicts with its definition.
NEVPNProtocolIPSec::sharedSecretReference is defined as:
A persistent keychain reference to a keychain item containing the IKE shared secret.
You need to create a keychain item of type kSecClassGenericPassword to use as the shared secret, and provide a persistent reference to the keychain item. A persistent reference is critical here, as it can be stored to disk or passed between processes, which is required for NEVPNManager to access the shared secret and connect your VPN. I suspect that although passwordReference seems to be set by a keychain item, it may not be returning a persistent reference either.
You will need to use SecItemCopyMatching with return type kSecReturnPersistentRef to achieve this.
Google+ Sign-In is now deprecated and Google is advising developers to use Google Sign-In instead. Using GIDSignIn class I was able to make users login via their Google account. Now I want to get the contact list including names and profile pictures from Google+. What is the ideal solution to this problem?
I found the following link helpful.
http://www.appcoda.com/google-sign-in-how-to/
Also this StackOverflow post gave an incomplete solution to the problem.
Get Google contacts using API on iOS
Please share your solutions.
With the help of the links I stated before, I was able to somewhat solve the problem.
First of all, I included AFNetworking into my Xcode project.
https://github.com/AFNetworking/AFNetworking
Secondly, in the AppDelegate.m I used the following code in the application:didFinishLaunchingWithOptions: method.
[[GIDSignIn sharedInstance] setClientID:
#"XXXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com"];
[[GIDSignIn sharedInstance] setShouldFetchBasicProfile:YES]; // default value
[[GIDSignIn sharedInstance] setScopes:#[#"https://www.googleapis.com/auth/plus.login",
#"https://www.googleapis.com/auth/plus.me"]];
Then in my FriendsViewController.m file where I show the list of people from Google+ including names and profile pictures in a collection view, I used the following code.
if ([[GIDSignIn sharedInstance] hasAuthInKeychain])
{
NSString * urlString = [NSString stringWithFormat:
#"https://www.googleapis.com/plus/v1/people/me/people/visible?access_token=%#",
[GIDSignIn sharedInstance].currentUser.authentication.accessToken];
// use connected in place of visible if you want only the people who use the app
AFJSONResponseSerializer * responseSerializer =
[AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
AFHTTPSessionManager * sessionManager = [AFHTTPSessionManager manager];
[sessionManager setResponseSerializer:responseSerializer];
[sessionManager GET:urlString parameters:nil progress:nil
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject)
{
if (responseObject != nil)
{
NSArray * arrayFriends = [responseObject valueForKey:#"items"];
for (id object in arrayFriends)
{
NSString * stringName = [object valueForKey:#"displayName"];
NSString * stringUrlProfilePicture =
[[object valueForKey:#"image"] valueForKey:#"url"];
NSURL * urlProfilePicture = [NSURL URLWithString:stringUrlProfilePicture];
NSData * dataProfilePicture = [NSData dataWithContentsOfURL:urlProfilePicture];
UIImage * imageProfilePicture = [UIImage imageWithData:dataProfilePicture];
NSMutableDictionary * dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:stringName forKey:#"name"];
[dictionary setObject:imageProfilePicture forKey:#"profilePicture"];
[self.arrayDictionaryFriends addObject:dictionary];
// self.arrayDictionaryFriends is used as the data source
}
[self.collectionViewFriends reloadData];
}
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error)
{
}];
}
Don't forget to implement the other points mentioned in the following links.
https://developers.google.com/identity/sign-in/ios/start-integrating
https://developers.google.com/identity/sign-in/ios/sign-in
The solution is not perfect as there is a delay when all the images are loaded from the urls. I would like to get feedback on the solution and idea of possible improvements.
I had created the new project which fetches the track of songs, so I tried to pass an array of SPTTracks to the player, please find it below.
self.player = [[SPTAudioStreamingController alloc] initWithClientId:auth.clientID];
self.player.diskCache = [[SPTDiskCache alloc] initWithCapacity:1024 * 1024 * 64];
NSString *trackURI = #"spotify:track:1zHlj4dQ8ZAtrayhuDDmkY";
[SPTTrack trackWithURI:[NSURL URLWithString:trackURI] accessToken:auth.session.accessToken market:#"ES" callback:^(NSError *error, id object) {
if (!error) {
SPTTrack *trackInfo = object;
NSArray *tracks = #[trackInfo];
[self.player playURIs:tracks fromIndex:0 callback:^(NSError *error) {
if (!error) {
} else {
NSLog(#"*** Failed to play track : %#", error);
}
}];
} else {
NSLog(#"Error %#", error);
}
}];
But I get crashes, whenever I run it. Please find error below while it is getting crash :
Simple Track Playback[254:24669] -[__NSCFConstantString absoluteString]: unrecognized selector sent to instance 0x1000c0508
I had also looked it on spotify api spotify_ios_sdk but I had found that one developer had already posted the same issue link.
If anyone has solved these type of issue then please provide your guidance.
Thanks in advanced.
Unfortunately, this method is not "equivalent", because the SPTTrack object returned inside the callback of [SPTTrack trackWithURI.... has many less informations.
I've tried some workaround, and I found that for me the solution is
1) Create a request for an SPTTrack object.
2) Pass that request to SPRequest performRequest callback.
3) Wait for the response, and eventually create a track from data (please find the below complete code).
self.player = [[SPTAudioStreamingController alloc] initWithClientId:auth.clientID];
self.player.diskCache = [[SPTDiskCache alloc] initWithCapacity:1024 * 1024 * 64];
NSString *market = [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
NSURLRequest *request = [SPTTrack createRequestForTrack:[NSURL URLWithString:#"spotify:track:1zHlj4dQ8ZAtrayhuDDmkY"]
withAccessToken:auth.session.accessToken
market:market
error:nil];
[[SPTRequest sharedHandler] performRequest:request
callback:^(NSError *error, NSURLResponse *response, NSData *data) {
if (!error) {
NSError *parsingError = nil;
SPTTrack *track = [SPTTrack trackFromData:data
withResponse:response
error:&parsingError];
self.arrURIs = #[track.playableUri];
[self.player playURIs:self.arrURIs fromIndex:0 callback:nil];
}
}];
Thanks "Kry256" for detail explaination.
I have an app that can send information to a server. This information is stacked up during the day (while the client uses the app), and when he so desires, he can hit the "update" button to send everything on the server.
This always worked fine until he recently had a flow increase and went from updating 10 objects to more than 100.
Obviously, the update takes more time, taht's not the issue.
The issue is, at some point, i'm getting
Error: Error Domain=NSURLErrorDomain Code=-1001 "La requête a expiré."
UserInfo=0x189874b0 {NSErrorFailingURLStringKey=http://www.*********.be/upload,
NSErrorFailingURLKey=http://www.************.be/upload,
NSLocalizedDescription=La requête a expiré.,
NSUnderlyingError=0x189abd70 "La requête a expiré."}
For the frenchophobes, " The request has expired " is what i get back, and i've hidden the url with ****, as you noticed.
Now, i've tried locally, it works fine with a small update, but when i loop 150 times on my update (i send 150 times the same thing), at some point i just get the above error X times. This error does not specificall occur with all the last items, it can be 20 in the middle, or 30, etc.
Is there a way i can change that?
Here is a piece of code that must be related to the issue.
// Set the max number of concurrent operations (threads)
//[operationQueue setMaxConcurrentOperationCount:3]; // Todo: try increasing max thread count
[operationQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount]; //dynamic thread count
self.queueCount = persons.count;
self.currentQueue = 1;
for (Person *person in persons) {
for (int i = 0 ; i<130 ; i++){ //this is where i try to break the app
[self createSendPersonOperation:person];
}}
Now what would probably work is put the last line in a "thing" that would slow down the process every 20 or so occurences, so the server or the app doesn't go crazy.
Is this possible? if so, how?
Note : I am a junior dev trying to get into a senior's code, and that guy is not available, so i'm open to all the help i can have.
Edit : also, do you think my error comes from a server-sided issue or is definitly an app-sided issue?
Edit : Complete HTTP request.
So for every person that is saved into the app, when the user decides to update, it does that for every Person in the array of persons.
- (void)createSendPersonOperation:(Person *)person
{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:#"text/html", #"application/json", nil];
NSDictionary *params = #{
#"email": person.email,
#"gender": person.gender,
#"language": person.language,
#"hasFacebook": person.hasFacebook,
#"sendPostalCard": person.sendPostalCard
};
NSLog(#"params: %#", params);
[manager POST:kURLUpdate parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
// Add picture to the form
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pictureFilePath = [documentsDirectory stringByAppendingPathComponent:person.picture];
NSURL *pictureURL = [NSURL fileURLWithPath:pictureFilePath];
[formData appendPartWithFileURL:pictureURL name:#"picture" error:nil];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success: %#", responseObject);
if ([responseObject isKindOfClass:[NSDictionary class]]) {
if ([responseObject objectForKey:#"error"]) {
NSLog(#"Error 1");
NSDictionary *error = [responseObject objectForKey:#"error"];
NSLog(#"Error message: %#", [error objectForKey:#"message"]);
} else {
// Set Person's sended attribute
person.sended = #YES;
[Person saveObject:[[PersistentStack sharedInstance] managedObjectContext] error:nil];
}
} else {
NSLog(#"Error 2");
}
[self decreaseQueueCount];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
NSLog(#"Parameter that failed : %#", [params objectForKey:#"email"]);
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Erreur"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"Fermer"
otherButtonTitles:nil];
[alertView show];
self.updateHud.mode = MBProgressHUDModeText;
self.updateHud.labelText = AMLocalizedString(#"update.failure.message", #"");
[self.updateHud hide:YES afterDelay:3];
}];
}
I don't really know the source of your problem, but if you think slowing the app will at least help you understand your problem you could do it with something like this:
NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:15];
while ([loopUntil timeIntervalSinceNow] > 0) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:loopUntil];
}
It will wait for 15 seconds before continue, so you can put this one after 20~30 requests as you suggested.
I really believe you should consider grouping your requests or something like that so you won't overload your server (if that is really your problem).