How do I discover what social media the user has chosen? - ios

How do I discover what social media the user has chosen, using Xamarin on iOS?
Look at my example below:
using (UIActivityViewController actController = new UIActivityViewController(activityTypes, null))
{
actController.ExcludedActivityTypes = new NSString[]
{
UIActivityType.AddToReadingList,
UIActivityType.AirDrop,
UIActivityType.AssignToContact,
UIActivityType.CopyToPasteboard,
UIActivityType.Print,
UIActivityType.SaveToCameraRoll
};
Version deviceVersion = new Version(UIDevice.CurrentDevice.SystemVersion);
if (deviceVersion >= iosVersion8) {
actController.PopoverPresentationController.SourceView = buttonView;
}
PresentViewController(actController, true, null);
}

Try setting the completion handler like so:
actController.CompletionHandler += (NSString arg1, bool arg2) => {
if (arg1.Equals(UIActivityType.PostToFacebook))
{
Console.Write ("YOU CHOOSE FACEBOOK!");
}
};

Related

How to properly update Android BillingFlowParams sku() to setSkuDetails()

here is the code can anyone tell how can I setSkuDetails()
as I was using vision one now I update it to 4
However, setSku and setType seem to be deprecated in the BillingFlowParams.Builder class. Instead, we should be using setSkuDetails(SkuDetails).
private void BillingFunction() {
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
// Establish connection to billing client
mBillingClient = BillingClient.newBuilder(MainActivity.this).setListener(MainActivity.this).build();
mBillingClient.startConnection(new BillingClientStateListener() {
#Override
public void onBillingSetupFinished(#NonNull BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// The billing client is ready. You can query purchases here.
getPricesMonthlyTime();
getPricesYearlyTime();
getPricesONeTime();
}
}
#Override
public void onBillingServiceDisconnected() {
//TODO implement your own retry policy
Toast.makeText(MainActivity.this, getResources().getString(R.string.billing_connection_failure), Toast.LENGTH_SHORT);
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
continue_button.setOnClickListener(view -> {
if (select_radio_one.getVisibility() == View.VISIBLE) {
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
.setSkuDetails()
.build();
BillingResult responseCode = mBillingClient.launchBillingFlow(MainActivity.this, flowParams);
brandDialogInAppPurchase.dismiss();
} else if (select_radio_two.getVisibility() == View.VISIBLE) {
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
.setSkuDetails()
.build();
BillingResult responseCode = mBillingClient.launchBillingFlow(MainActivity.this, flowParams);
brandDialogInAppPurchase.dismiss();
} else if (select_radio_three.getVisibility() == View.VISIBLE) {
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
.setSkuDetails()
.build();
BillingResult responseCode = mBillingClient.launchBillingFlow(MainActivity.this, flowParams);
brandDialogInAppPurchase.dismiss();
} else {
Toast.makeText(MainActivity.this, "Nothing selected", Toast.LENGTH_SHORT).show();
}
});
// queryPrefPurchases();
queryPurchases();
}
You should send the object skuDetail.
To do so you need to retrieve it by calling querySkuDetailsAsync().
fun querySkuDetails() {
val skuList = ArrayList<String>()
skuList.add("premium_upgrade")
skuList.add("gas")
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(SkuType.INAPP)
// leverage querySkuDetails Kotlin extension function
val skuDetailsResult = withContext(Dispatchers.IO) {
billingClient.querySkuDetails(params.build())
}
// Process the result.
}

iOS Xamarin: Attach Photo to Email Body

I am building an app, that allows user to take a picture, extract meta data and attach photo to Email + meta data information.
However the issue is that If you capture a photo from camera, the event does not return a ReferenceUrl, atleast I dont see one. I do get some form of URL but that doesn't work as intended. Here is my code:-
// Take a photo with the Camera //
partial void BtnCamera_TouchUpInside(UIButton sender)
{
UIImagePickerController imagePicker = new UIImagePickerController();
imagePicker.PrefersStatusBarHidden();
imagePicker.SourceType = UIImagePickerControllerSourceType.Camera;
// handle saving picture and extracting meta-data from picture //
imagePicker.FinishedPickingMedia += Handle_FinishedPickingMedia;
// present //
PresentViewController(imagePicker, true, () => { });
}
To save the image I call the SaveImageToPhone() from my FinishedPickingMedia handler. It looks like this:-
private static void SaveImagetoPhone(UIImagePickerMediaPickedEventArgs e)
{
NSUrl url = null;
void ImageData(PHAsset asset)
{
if (asset == null)
throw new Exception("PHAsset is null");
//PHImageManager.DefaultManager.RequestImageData(asset, null, (data, dataUti, orientation, info) =>
// {
// var urlX = info.ValueForKey(new NSString("PHImageFileURLKey"));
// url = info.ValueForKey(new NSString("PHImageFileURLKey")) as NSUrl;
// DataClass._fileURL = urlX.ToString();
// });
}
PHAsset phAsset;
if (e.ReferenceUrl == null)
{
e.OriginalImage?.SaveToPhotosAlbum((image, error) =>
{
if (error == null)
{
var options = new PHFetchOptions
{
FetchLimit = 1,
SortDescriptors = new[] { new NSSortDescriptor("creationDate", true) }
};
phAsset = PHAsset.FetchAssets(options).LastOrDefault() as PHAsset;
ImageData(phAsset);
}
});
}
else
{
phAsset = PHAsset.FetchAssets(new[] { e.ReferenceUrl }, null).FirstOrDefault() as PHAsset;
ImageData(phAsset);
}
}
In this function I have a couple of lines commented out, it is here where I was trying to get the reference URL for the Photo (unsuccessfully).
And finally my email () looks like this:-
partial void BtnMessageDone_TouchUpInside(UIButton sender)
{
MFMailComposeViewController mailController;
if (MFMailComposeViewController.CanSendMail)
{
StringBuilder htmlBodyMail = FormatEmailBody();
mailController = new MFMailComposeViewController();
// do mail operations here
mailController.SetToRecipients(new string[] { "xxyyzz#...com" });
mailController.SetSubject("mail test");
mailController.SetMessageBody(htmlBodyMail.ToString(), false);
UIImage img = UIImage.FromFile(DataClass._fileURL);
mailController.AddAttachmentData(img.AsJPEG(), "image/JPG", "Image.JPG");
mailController.Finished += (object s, MFComposeResultEventArgs args) =>
{
Console.WriteLine(args.Result.ToString());
args.Controller.DismissViewController(true, null);
};
this.PresentViewController(mailController, true, null);
}
Does anyone have any pointers on how to get the absolute path/reference URL of the photo taken by the in app camera and attach it to the email body ?
Use the Path property on the NSUrl class:
NSString urlString = new NSString("file:///stack/over%20flow/foobar.txt");
NSUrl myFileUrl = new NSUrl (urlString);
Console.WriteLine (myFileUrl.AbsoluteString);
string absPath = myFileUrl.Path;
Console.WriteLine (absPath);

Showing "Import with Instagram" in UIActivityViewController

I am trying to add Instagram in "Share To" functionality in my app. I have seen the Instagram's iPhone hooks documents. I have created custom UIActivty which works fine but my question is, is there a way to add "Import with Instagram" functionality as it can be seen in iOS's Photos app iOS Photo App:
In my app for some reason, it does not show that "Import with Instagram". my app Share view :
I do not want to share only with Instagram so no ".igo"
EDIT: All of this is specifically for iOS versions < 10. For some reasons Instagram Share Extension works fine (for my app) in devices with iOS >= 10.
EDIT: I am trying to share image and video with ".jpeg" and ".mov" formats respectively
I have seen/read that Instagram added share extension in release 8.2, so technically all the apps should show "Instagram" in share tray, i.e. it can be seen in Google Photos app.
public void NativeShareImage(UIView sourceView, CGRect sourceRect,
UIImage image, string shareCaption, string emailSubject)
{
string filename = Path.Combine(FileSystemUtils.GetTemporaryDataPath(), "Image.jpg");
NSError err = null;
using(var imgData = image.AsJPEG(JpgImageQuality))
{
if(imgData.Save(filename, false, out err))
{
Logger.Information("Image saved before native share as {FileName}", filename);
}
else
{
Logger.Error("Image NOT saved before native share as to path {FileName}. {Error}", filename, err.Description);
return;
}
}
// this are the items that needs to be shared
// Instagram ignores the caption, that is known
var activityItems = new List<NSObject>
{
new NSString(shareCaption),
new NSUrl(new Uri(filename).AbsoluteUri)
};
// Here i add the custom UIActivity for Instagram
UIActivity[] applicationActivities =
{
new InstagramActivity(image, sourceRect, sourceView),
}
var activityViewController = new UIActivityViewController(activityItems.ToArray(), applicationActivities);
activityViewController.SetValueForKey(new NSString(emailSubject), new NSString("subject"));
activityViewController.CompletionWithItemsHandler = (activityType, completed, returnedItems, error) =>
{
UserSharedTo(activityType, completed);
};
// Hide some of the less used activity types so that Instagram shows up in the list. Otherwise it's pushed off the activity view
// and the user has to scroll to see it.
activityViewController.ExcludedActivityTypes = new[] { UIActivityType.AssignToContact, UIActivityType.CopyToPasteboard, UIActivityType.Print };
if(UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone)
{
PresentViewController(activityViewController, true, null);
}
else
{
activityViewController.ModalPresentationStyle = UIModalPresentationStyle.Popover;
PresentViewController(activityViewController, true, null);
// Get the popover presentation controller and configure it.
UIPopoverPresentationController presentationController = activityViewController.PopoverPresentationController;
presentationController.PermittedArrowDirections = UIPopoverArrowDirection.Down;
presentationController.SourceRect = sourceRect;
presentationController.SourceView = sourceView;
}
}
// when opening custom activity use ".igo" to only show instagram
public class InstagramActivity : UIActivity
{
public InstagramActivity(UIImage imageToShare, CGRect frame, UIView view, string shareCaption = "")
{
_ImageToShare = imageToShare;
_Frame = frame;
_View = view;
}
public override UIImage Image { get { return UIImage.FromBundle("Instagram"); } }
public override string Title { get { return "Instagram"; } }
public override NSString Type { get { return new NSString("PostToInstagram"); } }
public string Caption { get; set; }
public override bool CanPerform(NSObject[] activityItems)
{
return UIApplication.SharedApplication.CanOpenUrl(NSUrl.FromString("instagram://app"));
}
public override void Prepare(NSObject[] activityItems)
{
}
public override void Perform()
{
string filename = Path.Combine(FileSystemUtils.GetTemporaryDataPath(), "Image.igo");
NSError err = null;
using(var imgData = _ImageToShare.AsJPEG(JpgImageQuality))
{
if(imgData.Save(filename, false, out err))
{
Logger.Information("Instagram image saved as {FileName}", filename);
}
else
{
Logger.Error("Instagram image NOT saved as to path {FileName}. {Error}", filename, err.Description);
Finished(false);
return;
}
}
var url = NSUrl.FromFilename(filename);
_DocumentController = UIDocumentInteractionController.FromUrl(url);
_DocumentController.DidEndSendingToApplication += (o, e) => Finished(true);
_DocumentController.Uti = "com.instagram.exclusivegram";
if(!string.IsNullOrEmpty(ShareCaption))
{
_DocumentController.Annotation = NSDictionary.FromObjectAndKey(new NSString(ShareCaption), new NSString("InstagramCaption"));
}
_DocumentController.PresentOpenInMenu(_Frame, _View, true);
}
UIImage _ImageToShare;
CGRect _Frame;
UIView _View;
UIDocumentInteractionController _DocumentController;
}

Monotouch : pause application unit dialog response

How can i pause application for prevention from running next method unit client does not selected dialog buttons?
For example i am showing location update dialog for accessing location service and i want to pause my application for dialog response
public CLLocation UpdateUserLocation()
{
CLLocation currentLocation = null;
CLLocationManager LocMgr = new CLLocationManager();
if (CLLocationManager.LocationServicesEnabled)
{
if (UIDevice.CurrentDevice.CheckSystemVersion (6, 0))
{
LocMgr.LocationsUpdated += (object sender, CLLocationsUpdatedEventArgs e) =>
{
currentLocation = e.Locations [e.Locations.Length - 1];
};
}
else
{
LocMgr.UpdatedLocation += (object sender, CLLocationUpdatedEventArgs e) =>
{
currentLocation = e.NewLocation;
};
}
LocMgr.StartUpdatingLocation ();
LocMgr.Failed += (object sender, NSErrorEventArgs e) =>
{
Console.WriteLine (e.Error);
};
}
else
{
currentLocation = null;
Console.WriteLine ("Location services not enabled, please enable this in your Settings");
}
if (currentLocation != null)
{
LocationDetector.Instance.UpdateCurrentArea (new MyLatLng (currentLocation.Coordinate.Latitude, currentLocation.Coordinate.Longitude));
}
return currentLocation;
}
If I am understanding your question correctly.
When you display a dialog box, you are wanting to stop execution of the current method from further executing until the user selects a dialog box response.
Once they have selected a response, you would then like to continue execution of the code in the same function, effectively achieving your 'pause' that you are after.
To achieve this in iOS you can use a TaskCompletionSource.
In the example below it shows a dialog box first, asking the user if they want some coffee and then waits for the user to respond.
Once the user responds, it then continues execution, within the same function, and displays a further message box that is dependent on the selection that the user made.
UIButton objButton1 = new UIButton (UIButtonType.RoundedRect);
objButton1.SetTitle ("Click Me", UIControlState.Normal);
objButton1.TouchUpInside += (async (o2, e2) => {
int intCoffeeDispenserResponse = await ShowCoffeeDispenserDialogBox();
//
switch (intCoffeeDispenserResponse)
{
case 0:
UIAlertView objUIAlertView1 = new UIAlertView();
objUIAlertView1.Title = "Coffee Dispenser";
objUIAlertView1.Message = "I hope you enjoy the coffee.";
objUIAlertView1.AddButton("OK");
objUIAlertView1.Show();
break;
case 1:
UIAlertView objUIAlertView2 = new UIAlertView();
objUIAlertView2.Title = "Coffee Dispenser";
objUIAlertView2.Message = "OK - Please come back later when you do.";
objUIAlertView2.AddButton("OK");
objUIAlertView2.Show();
break;
}
});
//
View = objButton1;
private Task<int> ShowCoffeeDispenserDialogBox()
{
TaskCompletionSource<int> objTaskCompletionSource1 = new TaskCompletionSource<int> ();
//
UIAlertView objUIAlertView1 = new UIAlertView();
objUIAlertView1.Title = "Coffee Dispenser";
objUIAlertView1.Message = "Do you want some coffee?";
objUIAlertView1.AddButton("Yes");
objUIAlertView1.AddButton("No");
//
objUIAlertView1.Clicked += ((o2, e2) => {
objTaskCompletionSource1.SetResult(e2.ButtonIndex);
});
//
objUIAlertView1.Show();
//
return objTaskCompletionSource1.Task;
}

Cordova Media Plugin doesn't implement audioPlayerEndInterruption

I have created an iOS app that plays audio while the app is running in the background. If the audio is ever interrupted (i.e.: phone call), the audio stops and never resumes.
I think this is because the cordova media plugin doesn't implement audioPlayerEndInterruption
I'm good with Javascript but know almost nothing about Objective-C. Does anyone have advice on how to add this functionality?
Is there a different media plugin that implements audioPlayerEndInterruption, or is there a simple way to incorporate audioPlayerEndInterruption into the cordova plugin?
CDVSound.h
-modify:add: , MEDIA_END_INTERRUPT = 5
enum CDVMediaStates {
MEDIA_NONE = 0,
MEDIA_STARTING = 1,
MEDIA_RUNNING = 2,
MEDIA_PAUSED = 3,
MEDIA_STOPPED = 4,
MEDIA_END_INTERRUPT = 5
};
CDVSound.m
-add:
- (void)audioPlayerEndInterruption:(AVAudioPlayer*)player successfully:(BOOL)flag
{
CDVAudioPlayer* aPlayer = (CDVAudioPlayer*)player;
NSString* mediaId = aPlayer.mediaId;
CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId];
NSString* jsString = nil;
if (audioFile != nil) {
NSLog(#"Ended Interruption of playing audio sample '%#'", audioFile.resourcePath);
}
if (flag) {
jsString = [NSString stringWithFormat:#"%#(\"%#\",%d,%d);", #"cordova.require('org.apache.cordova.media.Media').onStatus", mediaId, MEDIA_STATE, MEDIA_END_INTERRUPT];
} else {
jsString = [NSString stringWithFormat:#"%#(\"%#\",%d,%#);", #"cordova.require('org.apache.cordova.media.Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_DECODE message:nil]];
}
[self.commandDelegate evalJs:jsString];
}
Media.js
-modify:add: Media.MEDIA_END_INTERRUPT = 5; AND , "EndInterrupt"
// Media states
Media.MEDIA_NONE = 0;
Media.MEDIA_STARTING = 1;
Media.MEDIA_RUNNING = 2;
Media.MEDIA_PAUSED = 3;
Media.MEDIA_STOPPED = 4;
Media.MEDIA_END_INTERRUPT = 5;
Media.MEDIA_MSG = ["None", "Starting", "Running", "Paused", "Stopped", "EndInterrupt"];
Then find Media.onStatus = function(id, msgType, value) { and add a conditional in the case Media.MEDIA_STATE : block...
if(value == Media.MEDIA_END_INTERRUPT) {
//do whatever you want
}
Just following up here. I ended up writing a plugin for this that overwrites some of the default cordova media plugin (v0.2.12) methods. I'm posting a link here, but the code is a mess. I was just trying to get something that works and not really planning on sharing. But here it is (no documentation provided, sorry):
https://github.com/stevethorson/Interruptible-Cordova-Media.git
I fixed the problem from within the media plugin itself, using the getCurrentPosition method I was able to detect if the streaming gets intrupted by a phone call or voicemail.. and then stop and rePlay the audio again. I hope this helps someone I took me forever to get this working with the media plugin and shoutcast.
var mediaplayer = new Media(streamingUrl, mediaSuccess, mediaFail, mediaState);
mediaplayer.play({playAudioWhenScreenIsLocked :true});
var prevPos = 0;
var mediaTimer = setInterval(function () {
// get media position
mediaplayer.getCurrentPosition(
// success callback
function (currentposition) {
if (currentposition > prevPos) {
prevPos = currentposition;
} else if (currentposition === prevPos) {
stop();
play();
} else {
console.log("can't get pos");
}
},
// error callback
function (e) {
alert+("Error getting pos=" + e);
}
);
}, 5000);

Resources