For some reason game center matchMaking works well when both devices on the same wifi but does not work when one of the devices is on 3g (the devices keep searching and cannot find each other).
I am using:
1. iPad 2 with iOS 7.0.4 with sandbox account (compatible to the device's app store account)
2. Iphone 4s with iOS 7.0.4 with sandbox account (compatible to the device's app store account but different from the iPad account).
The code that create the match goes like this:
- (IBAction)continueButtonPressed:(id)sender {
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = 2;
request.maxPlayers = 4;
request.defaultNumberOfPlayers = 2;
if(([[self.gameTypeSegmentControl objectAtIndex:0] selectedSegmentIndex] == 0) ||
([[self.gameTypeSegmentControl objectAtIndex:1] selectedSegmentIndex] == 0))
{
int temp = [self.allLanguages indexOfObject:[[self.languages objectAtIndex:selectedRow] primaryLanguage]];
if ((temp > 0) && (temp <= self.allLanguages.count))
{
request.playerGroup = temp;
}else
{
request.playerGroup = ENGLISH_US_LANG;//50
}
}
if(([[self.gameTypeSegmentControl objectAtIndex:0] selectedSegmentIndex] == 1) ||
([[self.gameTypeSegmentControl objectAtIndex:1] selectedSegmentIndex] == 1))
{
request.playerGroup = 255;
}
if (isJoining)// Not the creator of the game
{
request.playerAttributes = JOIN_ATTRIBUTE;
[[GKMatchmaker sharedMatchmaker] findMatchForRequest:request withCompletionHandler:^(GKMatch *match, NSError *error) {
if (error)
{
NSLog(#"findMatchForRequest ended with error");
// Process the error.
}
else if (match != nil)
{
self.myMatch = match; // Use a retaining property to retain the match.
match.delegate = self;
if (!self.matchStarted && match.expectedPlayerCount == 0)
{
self.matchStarted = YES;
NSLog(#"match begin");
// Insert game-specific code to begin the match.
}
}
}];
}else //The creator of the game
{
request.playerAttributes = CREATE_ATTRIBUTE;
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithMatchRequest:request];
mmvc.matchmakerDelegate = self;
[self presentViewController:mmvc animated:YES completion:nil];
}
}
Any idea what causing the problem???
Related
I'm trying to create a Turn-Based GameCenter multiplayer game and I can't connect 2 players in a match:
I'm connecting with a custom UI and both devices (iPhone and simulator) are running iOS 9.1.
I run on a device and after I run findMatch it creates a new room with me and a player with playerID nil which I read it's normal but when I run on the other device it also does same stuff. Devices are not in same room.
What am I doing wrong?
I am using the following code:
-(void)searchForTurnBasedMatch{
GKMatchRequest *request = [[GKMatchRequest alloc] init];
// request.minPlayers = 2;
request.maxPlayers = 4;
request.inviteeResponseHandler = ^(NSString *playerID, GKInviteeResponse response)
{
if (response == GKInviteeResponseAccepted)
{
NSLog(#"playerCeva");
}
};
[GKTurnBasedMatch findMatchForRequest:request withCompletionHandler:^(GKTurnBasedMatch * _Nullable match, NSError * _Nullable error) {
if (error)
{
NSLog(#"eroare la gasire meci: %#",error);
}
else if (match != nil)
{
self.myTurnBasedMatch = match;
[self resumeMatch:match];
}
}];
}
- (void)resumeMatch:(GKTurnBasedMatch *)match {
self.myTurnBasedMatch = match;
NSLog(#"Created/Selected match");
NSLog(#"ID: %#\tCreated: %#", match.matchID, match.creationDate);
GKTurnBasedParticipant *firstParticipant = [match.participants objectAtIndex:0];
if (firstParticipant.lastTurnDate != NULL) {
if ([match.currentParticipant.playerID isEqualToString:[GKLocalPlayer localPlayer].playerID]) {
NSLog(#"Taking turn ...");
} else {
NSLog(#"Not my turn ...");
}
} else {
NSLog(#"New game ...");
}
}
Here's the source code for the method that appears to be causing the leak.
- (void)search:(CDVInvokedUrlCommand*)command
{
NSString* callbackId = command.callbackId;
NSArray* fields = [command argumentAtIndex:0];
NSDictionary* findOptions = [command argumentAtIndex:1 withDefault:[NSNull null]];
[self.commandDelegate runInBackground:^{
// from Apple: Important You must ensure that an instance of ABAddressBookRef is used by only one thread.
// which is why address book is created within the dispatch queue.
// more details here: http: //blog.byadrian.net/2012/05/05/ios-addressbook-framework-and-gcd/
CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init];
CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles
// it gets uglier, block within block.....
[abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errCode) {
if (addrBook == NULL) {
// permission was denied or other error - return error
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errCode ? (int)errCode.errorCode:UNKNOWN_ERROR];
[weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
return;
}
NSArray* foundRecords = nil;
// get the findOptions values
BOOL multiple = NO; // default is false
NSString* filter = nil;
NSArray* desiredFields = nil;
if (![findOptions isKindOfClass:[NSNull class]]) {
id value = nil;
filter = (NSString*)[findOptions objectForKey:#"filter"];
value = [findOptions objectForKey:#"multiple"];
if ([value isKindOfClass:[NSNumber class]]) {
// multiple is a boolean that will come through as an NSNumber
multiple = [(NSNumber*)value boolValue];
// NSLog(#"multiple is: %d", multiple);
}
desiredFields = [findOptions objectForKey:#"desiredFields"];
// return all fields if desired fields are not explicitly defined
if (desiredFields == nil || desiredFields.count == 0) {
desiredFields = [NSArray arrayWithObjects:#"*", nil];
}
}
NSDictionary* searchFields = [[CDVContact class] calcReturnFields:fields];
NSDictionary* returnFields = [[CDVContact class] calcReturnFields:desiredFields];
NSMutableArray* matches = nil;
if (!filter || [filter isEqualToString:#""]) {
// get all records
foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook);
if (foundRecords && ([foundRecords count] > 0)) {
// create Contacts and put into matches array
// doesn't make sense to ask for all records when multiple == NO but better check
int xferCount = multiple == YES ? (int)[foundRecords count] : 1;
matches = [NSMutableArray arrayWithCapacity:xferCount];
for (int k = 0; k < xferCount; k++) {
CDVContact* xferContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:k]];
[matches addObject:xferContact];
xferContact = nil;
}
}
} else {
foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook);
matches = [NSMutableArray arrayWithCapacity:1];
BOOL bFound = NO;
int testCount = (int)[foundRecords count];
for (int j = 0; j < testCount; j++) {
CDVContact* testContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:j]];
if (testContact) {
bFound = [testContact foundValue:filter inFields:searchFields];
if (bFound) {
[matches addObject:testContact];
}
testContact = nil;
}
}
}
NSMutableArray* returnContacts = [NSMutableArray arrayWithCapacity:1];
if ((matches != nil) && ([matches count] > 0)) {
// convert to JS Contacts format and return in callback
// - returnFields determines what properties to return
#autoreleasepool {
int count = multiple == YES ? (int)[matches count] : 1;
for (int i = 0; i < count; i++) {
CDVContact* newContact = [matches objectAtIndex:i];
NSDictionary* aContact = [newContact toDictionary:returnFields];
[returnContacts addObject:aContact];
}
}
}
// return found contacts (array is empty if no contacts found)
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:returnContacts];
[weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
// NSLog(#"findCallback string: %#", jsString);
if (addrBook) {
CFRelease(addrBook);
}
}];
}]; // end of workQueue block
return;
}
The specific line that is doing most of the leaking is foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook);, but this is confusing, given that the correct __bridge_transfer call is used. What's going on here?
I have followed a great tutorial online on how to use Game Center in your iOS apps. It can be found here: http://code.tutsplus.com/tutorials/ios-sdk-game-center-achievements-and-leaderboards-part-2--mobile-5801
However the code for submitting an achievement seems to unlock achievements which have already been unlocked and I don't understand why. Here is my method which deals with a achievements:
-(void)submitAchievement:(NSString*)identifier percentComplete:(double)percentComplete {
if (self.earnedAchievementCache == NULL) {
[GKAchievement loadAchievementsWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error == NULL) {
NSMutableDictionary *tempCache = [NSMutableDictionary dictionaryWithCapacity: [scores count]];
for (GKAchievement *score in tempCache) {
[tempCache setObject: score forKey: score.identifier];
}
self.earnedAchievementCache = tempCache;
[self submitAchievement:identifier percentComplete: percentComplete];
}
else {
// Something broke loading the achievement list. Error out, and we'll try again the next time achievements submit.
[self callDelegateOnMainThread: #selector(achievementSubmitted:error:) withArg: NULL error: error];
}
}];
}
else {
// Search the list for the ID we're using...
GKAchievement *achievement = [self.earnedAchievementCache objectForKey:identifier];
if (achievement != NULL) {
if ((achievement.percentComplete >= 100.0) || (achievement.percentComplete >= percentComplete)) {
// Achievement has already been earned so we're done.
achievement = NULL;
}
achievement.percentComplete = percentComplete;
}
else {
achievement = [[[GKAchievement alloc] initWithIdentifier:identifier] autorelease];
achievement.percentComplete = percentComplete;
// Add achievement to achievement cache...
[self.earnedAchievementCache setObject:achievement forKey:achievement.identifier];
}
if (achievement != NULL) {
// Submit the Achievement...
[achievement reportAchievementWithCompletionHandler: ^(NSError *error) {
[self callDelegateOnMainThread:#selector(achievementSubmitted:error:) withArg:achievement error:error];
}];
}
}
}
Thanks for your time, Dan.
Can you try this code and see the log. I added NSLog statements to see if the code detects achievement is completed and sets the achievement to nil. Also delete NULL from the code. Let me know how it works out.
-(void)submitAchievement:(NSString*)identifier percentComplete:(double)percentComplete {
if (!self.earnedAchievementCache) {
[GKAchievement loadAchievementsWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (!error) {
NSMutableDictionary *tempCache = [NSMutableDictionary dictionaryWithCapacity: [scores count]];
for (GKAchievement *score in scores) { // the error is here
[tempCache setObject: score forKey: score.identifier];
}
self.earnedAchievementCache = tempCache;
[self submitAchievement:identifier percentComplete: percentComplete];
}
else {
// Something broke loading the achievement list. Error out, and we'll try again the next time achievements submit.
[self callDelegateOnMainThread: #selector(achievementSubmitted:error:) withArg: NULL error: error];
}
}];
}else {
// Search the list for the ID we're using...
GKAchievement *achievement = [self.earnedAchievementCache objectForKey:identifier];
NSLog(#"achievement %f",achievement.percentComplete);
if (achievement) {
if ((achievement.percentComplete >= 100.0) || (achievement.percentComplete >= percentComplete)) {
NSLog(#"Achievement has already been earned so we're done.");
achievement = nil;
}else{
achievement.percentComplete = percentComplete;
}
}else {
achievement = [[[GKAchievement alloc] initWithIdentifier:identifier] autorelease];
achievement.percentComplete = percentComplete;
// Add achievement to achievement cache...
[self.earnedAchievementCache setObject:achievement forKey:achievement.identifier];
}
if (achievement) {
NSLog(#"Submit the Achievement...");
[achievement reportAchievementWithCompletionHandler: ^(NSError *error) {
[self callDelegateOnMainThread:#selector(achievementSubmitted:error:) withArg:achievement error:error];
}];
}
}
}
I have a code to know which beacon is the closest, but I have a problem when a beacon's accuracy is -1.00000, the the app takes the second one.
So there is a bucle that seek for the closest beacon looking for others and comparing the one closest with the others found around. Then when I know which is the closest one I show it's view to the user, but when other beacon is closer to the ipad the view is close and the view is shown.
I'm using iOS 7.1 and 7.0.4 on 2 iPads, first is iPad3 and the second one is an iPad Mini Retina.
Here you have the code:
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}
- (void)initRegion {
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:#"00000000-0000-0000-0000-000000000002"];
self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:#"com.devfright.myRegion"];
[self.locationManager startMonitoringForRegion:self.beaconRegion];
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
NSLog(#"Beacon Found");
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
NSLog(#"Left Region");
[self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
}
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
CLBeacon *beacon = [[CLBeacon alloc] init];
CLBeacon *closestBeacon = [[CLBeacon alloc] init];
closestBeacon = [beacons lastObject];
//Search for the closest and show the view
for (int i=0; i<beacons.count; i++) {
beacon = beacons[i];
if (beacon.accuracy < closestBeacon.accuracy && beacon.accuracy != -1.000000 && beacon.minor != closestBeacon.minor && beacon.proximity != CLProximityFar) {
closestBeacon = beacons[i];
//NSString *closeAccuracy = closestBeacon.minor.stringValue;
}
NSLog(#"\nActualBeacon:%#\nAccuracy:%f", beacon.minor.stringValue,beacon.accuracy);
NSLog(#"\nCloserBeacon: %#\nAccuracy:%f", closestBeacon.minor.stringValue, closestBeacon.accuracy);
}
NSLog(#"\nClosestBeacon: %#", closestBeacon.minor.stringValue);
if (viewShown == NO) {
if ([closestBeacon.minor.stringValue isEqual: #"1"]) {
actualSection = 1;
[self immediateDetection];
}else if ([closestBeacon.minor.stringValue isEqual: #"2"]){
actualSection = 2;
[self immediateDetection];
}else if ([closestBeacon.minor.stringValue isEqual: #"3"]){
actualSection = 3;
[self immediateDetection];
}else if ([closestBeacon.minor.stringValue isEqual: #"4"]){
actualSection = 4;
[self immediateDetection];
}else if ([closestBeacon.minor.stringValue isEqual: #"5"]){
actualSection = 5;
[self immediateDetection];
}else if ([closestBeacon.minor.stringValue isEqual: #"6"]){
actualSection = 6;
[self immediateDetection];
NSLog(#"6");
}else if ([closestBeacon.minor.stringValue isEqual: #"7"]){
actualSection = 7;
[self immediateDetection];
NSLog(#"7");
}else if ([closestBeacon.minor.stringValue isEqual: #"8"]){
actualSection = 8;
[self immediateDetection];
NSLog(#"8");
}else if ([closestBeacon.minor.stringValue isEqual: #"9"]){
actualSection = 9;
[self immediateDetection];
NSLog(#"9");
}else if ([closestBeacon.minor.stringValue isEqual: #"10"]){
actualSection = 10;
[self immediateDetection];
NSLog(#"10");
}else if ([closestBeacon.minor.stringValue isEqual: #"11"]){
actualSection = 11;
[self immediateDetection];
NSLog(#"11");
}else if ([closestBeacon.minor.stringValue isEqual: #"30"]){
actualSection = 30;
[self immediateDetection];
}
} else if (viewShown == YES) {
if (closestBeacon.minor.integerValue != actualSection) {
//Alarm: Beacon 11
// if (closestBeacon.minor.integerValue != 11 || closestBeacon.minor.integerValue != 10) {
[self dismissViewControllerAnimated:NO completion:nil];
//actualSection = 0;
viewShown = NO;
// }
}
}
}
- (void)immediateDetection
{
viewShown = YES;
if (self.presentedViewController)
{
return;
}
if (actualSection == 1) {
SectionViewController *sectionView = [[SectionViewController alloc] init];
sectionView.section = 1;
[self presentViewController:sectionView animated:NO completion:nil];
sectionView.lbl_name.text = self.lbl_name.text;
}else if (actualSection == 2){
SectionViewController *sectionView = [[SectionViewController alloc] init];
sectionView.section = 2;
[self presentViewController:sectionView animated:NO completion:nil];
sectionView.lbl_name.text = self.lbl_name.text;
}else if (actualSection == 3){
SectionViewController *sectionView = [[SectionViewController alloc] init];
sectionView.section = 3;
[self presentViewController:sectionView animated:NO completion:nil];
sectionView.lbl_name.text = self.lbl_name.text;
}else if (actualSection == 4){
SectionViewController *sectionView = [[SectionViewController alloc] init];
sectionView.section = 4;
[self presentViewController:sectionView animated:NO completion:nil];
sectionView.lbl_name.text = self.lbl_name.text;
}else if (actualSection == 5){
SectionViewController *sectionView = [[SectionViewController alloc] init];
sectionView.section = 5;
[self presentViewController:sectionView animated:NO completion:nil];
sectionView.lbl_name.text = self.lbl_name.text;
}else if (actualSection == 6){
SectionViewController *sectionView = [[SectionViewController alloc] init];
sectionView.section = 6;
[self presentViewController:sectionView animated:NO completion:nil];
sectionView.lbl_name.text = self.lbl_name.text;
}else if (actualSection == 7){
SectionViewController *sectionView = [[SectionViewController alloc] init];
sectionView.section = 7;
[self presentViewController:sectionView animated:NO completion:nil];
sectionView.lbl_name.text = self.lbl_name.text;
}else if (actualSection == 8){
SectionViewController *sectionView = [[SectionViewController alloc] init];
sectionView.section = 8;
[self presentViewController:sectionView animated:NO completion:nil];
sectionView.lbl_name.text = self.lbl_name.text;
}else if (actualSection == 9){
SectionViewController *sectionView = [[SectionViewController alloc] init];
sectionView.section = 9;
[self presentViewController:sectionView animated:NO completion:nil];
sectionView.lbl_name.text = self.lbl_name.text;
}else if (actualSection == 10){
ThiefAlarmViewController *thiefAlarmView = [[ThiefAlarmViewController alloc] init];
[self presentViewController:thiefAlarmView animated:NO completion:nil];
}else if (actualSection == 11){
ThiefAlarmViewController *thiefAlarmView = [[ThiefAlarmViewController alloc] init];
[self presentViewController:thiefAlarmView animated:NO completion:nil];
}else if (actualSection == 30){
SectionViewController *sectionView = [[SectionViewController alloc] init];
sectionView.section = 30;
[self presentViewController:sectionView animated:NO completion:nil];
sectionView.lbl_name.text = self.lbl_name.text;
}
}
When I know the closest iBeacon I show it's view, but when it's accuracy is -1.00000 and compare to others the app takes the second one cause the first has it's accuracy = -1.00000 .
Hope anyone can help me cause I don't know what to do, maybe this is an iBeacon problem, but I think there is a solution for this issue.
Thanks.
locationManager:didRangeBeacons:inRegion: will return you a list of beacons in proximity order. That is, the first beacon in the list will be the nearest to you.
However, there is one exception to this rule: if any beacons have a proximity of Unknown, then they will be at the top of the list (because their accuracy is -1). To account for this, simply filter out any Unknown beacons, and then pick the first in the list:
beacons = [beacons filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"proximity != %d", CLProximityUnknown]];
CLBeacon *nearestBeacon = [beacons firstObject];
First of all:
Replace your long else/if of locationManager:didRangeBeacons:inRegion: with:
if (([closestBeacon.minor intValue] > 0 && [closestBeacon.minor intValue] <= 11) || [closestBeacon.minor intValue] == 30)
{
actualSection = [closestBeacon.minor intValue];
[self immediateDetection];
}
Replace your long else/if in immediateDetection with:
if ((actualSection > 0 && actualSection < 10 || actualSection == 30)
{
SectionViewController *sectionView = [[SectionViewController alloc] init];
sectionView.section = actualSection;
[self presentViewController:sectionView animated:NO completion:nil];
sectionView.lbl_name.text = self.lbl_name.text;
}
else if (actualSection == 10 || actualSection == 11)
{
ThiefAlarmViewController *thiefAlarmView = [[ThiefAlarmViewController alloc] init];
[self presentViewController:thiefAlarmView animated:NO completion:nil];
}
else
{
}
That should save you a lot of code.
For your issue, you could to this:
NSPredicate *predicateIrrelevantBeacons = [NSPredicate predicateWithFormat:#"(self.accuracy != -1) AND ((self.proximity != %d) OR (self.proximity != %d))", CLProximityFar,CLProximityUnknown];
NSArray *relevantsBeacons = [beacons filteredArrayUsingPredicate: predicateIrrelevantBeacons];
NSPredicate *predicateMin = [NSPredicate predicateWithFormat:#"self.accuracy == %#.#min.accuracy", relevantsBeacons];
CLBeacon *closestBeacon = nil;
NSArray *closestArray = [[relevantsBeacons filteredArrayUsingPredicate:predicateMin];
if ([closestArray count] > 0)
closestBeacon = [closestArray objectAtIndex:0];
if (closestBeacon)
{ //Do your thing }
else
{//No relevant close beacon}
In addition to filtering out proximity values of -1, you also have to take into account cases where certain iBeacons periodically do not appear in a callback to didRangeBeacons: inRegion. This can happen due to radio interference, especially for battery powered beacons that do not transmit advertisements very frequently.
To solve this, you need to keep your own list of recently seen beacons, and track any beacons that have been seen in the last few seconds. If one of the beacons has a proximity of -1, you can either not put it in the list, or re-use the last known non -1 proximity value if it does not exist.
Another consideration that you need to take into account is that the proximity value will bounce around quite a bit. You may need to add some hysteresis logic to your algorithm so which beacon is the closest doesn't bounce back and forth every second. The specifics of how you want to do this depend on your use case.
PhoneGap offers a plug-in for recording video, but this plug-in seems to force users to leave the app for the Camera app in order to record video.
Is it possible to initiate and stop video recording without leaving the app?
The two methods below are the primary methods we are using (rest of plug-in is viewable from the link above) to capture video. How should we modify this to allow recording from the front camera, without leaving the app, when the user taps a button?
Can anyone provide guidance please? Thanks.
Capture.m:
- (void)captureVideo:(CDVInvokedUrlCommand*)command
{
NSString* callbackId = command.callbackId;
NSDictionary* options = [command.arguments objectAtIndex:0];
if ([options isKindOfClass:[NSNull class]]) {
options = [NSDictionary dictionary];
}
// options could contain limit, duration and mode
// taking more than one video (limit) is only supported if provide own controls via cameraOverlayView property
NSNumber* duration = [options objectForKey:#"duration"];
NSString* mediaType = nil;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
// there is a camera, it is available, make sure it can do movies
pickerController = [[CDVImagePicker alloc] init];
NSArray* types = nil;
if ([UIImagePickerController respondsToSelector:#selector(availableMediaTypesForSourceType:)]) {
types = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
// NSLog(#"MediaTypes: %#", [types description]);
if ([types containsObject:(NSString*)kUTTypeMovie]) {
mediaType = (NSString*)kUTTypeMovie;
} else if ([types containsObject:(NSString*)kUTTypeVideo]) {
mediaType = (NSString*)kUTTypeVideo;
}
}
}
if (!mediaType) {
// don't have video camera return error
NSLog(#"Capture.captureVideo: video mode not available.");
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_NOT_SUPPORTED];
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
pickerController = nil;
} else {
pickerController.delegate = self;
pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
pickerController.allowsEditing = NO;
// iOS 3.0
pickerController.mediaTypes = [NSArray arrayWithObjects:mediaType, nil];
if ([mediaType isEqualToString:(NSString*)kUTTypeMovie]){
if (duration) {
pickerController.videoMaximumDuration = [duration doubleValue];
}
//NSLog(#"pickerController.videoMaximumDuration = %f", pickerController.videoMaximumDuration);
}
// iOS 4.0
if ([pickerController respondsToSelector:#selector(cameraCaptureMode)]) {
pickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo;
// pickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;
// pickerController.cameraDevice = UIImagePickerControllerCameraDeviceRear;
// pickerController.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto;
}
// CDVImagePicker specific property
pickerController.callbackId = callbackId;
SEL selector = NSSelectorFromString(#"presentViewController:animated:completion:");
if ([self.viewController respondsToSelector:selector]) {
[self.viewController presentViewController:pickerController animated:YES completion:nil];
} else {
// deprecated as of iOS >= 6.0
[self.viewController presentModalViewController:pickerController animated:YES];
}
}
}
- (CDVPluginResult*)processVideo:(NSString*)moviePath forCallbackId:(NSString*)callbackId
{
// save the movie to photo album (only avail as of iOS 3.1)
/* don't need, it should automatically get saved
NSLog(#"can save %#: %d ?", moviePath, UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(moviePath));
if (&UIVideoAtPathIsCompatibleWithSavedPhotosAlbum != NULL && UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(moviePath) == YES) {
NSLog(#"try to save movie");
UISaveVideoAtPathToSavedPhotosAlbum(moviePath, nil, nil, nil);
NSLog(#"finished saving movie");
}*/
// create MediaFile object
NSDictionary* fileDict = [self getMediaDictionaryFromPath:moviePath ofType:nil];
NSArray* fileArray = [NSArray arrayWithObject:fileDict];
return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:fileArray];
}