iOS Question Share to social media functionality - Help with inline objC

henrywood

Active Member
Licensed User
Longtime User
Hey !

I am trying to integrate social sharing functionality in my app through Objective C.

Could someone validate the methology - in particular the Objective C code ?

I would like to get an event in B4i when the user has completed sharing.

UPDATED: 09-05-2015: THIS VERSION DOES NOT WORK - PLEASE SEE POST #101 FOR A WORKING VERSION:
https://www.b4x.com/android/forum/t...elp-with-inline-objc.52849/page-6#post-336177

A BIG THANK YOU TO ALL WHO HELPED ME WITH THIS CODE !

Here is my code:

B4X:
'Code module

Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'Public variables can be accessed from all modules.

End Sub


#If OBJC

- (IBAction)shareToSocialMedia:(NSString *)txt (NSString *)url: (NSString *)image
{
   //NSString *text = @"How to add Facebook and Twitter sharing to an iOS app";
   NSString *text = txt;
   //NSURL *url = [NSURL URLWithString:@"http://roadfiresoftware.com/2014/02/how-to-add-facebook-and-twitter-sharing-to-an-ios-app/"];
   NSURL *url = [NSURL URLWithString:url];
   //UIImage *image = [UIImage imageNamed:@"roadfire-icon-square-200"];
   UIImage *image = [UIImage imageNamed:image];

   UIActivityViewController *controller =
   [[UIActivityViewController alloc]
   initWithActivityItems:@[text, url, image]
   applicationActivities:nil];

  controller.excludedActivityTypes = @[UIActivityTypePostToWeibo,
  UIActivityTypeMessage,
  UIActivityTypeMail,
  UIActivityTypePrint,
  UIActivityTypeCopyToPasteboard,
  UIActivityTypeAssignToContact,
  UIActivityTypeSaveToCameraRoll,
  UIActivityTypeAddToReadingList,
  UIActivityTypePostToFlickr,
  UIActivityTypePostToVimeo,
  UIActivityTypePostToTencentWeibo,
  UIActivityTypeAirDrop];

   [self presentViewController:controller animated:YES completion:^{
     [self sharedone];
   }];
}

- (void)sharedone:
{
   int status = 1;
   [B4IObjectWrapper raiseEvent:self :@"onsharingdone:" :@[@((int)status)]];
   //[B4IObjectWrapper raiseEventFromDifferentThread:self :@"onsharingdone:" :@[@((int)status)]];

}

#end if

Sub onSharingDone(Status As Int)
   Log("onSharingDone: Status = " & Status)
End Sub

Sub ShareToSocialMedia(txt As String, theURL As String, imageFile As String)

   Dim NativeMe As NativeObject = Me
   NativeMe.RunMethod("shareToSocialMedia:", Array As Object(txt, theURL, imageFile))

End Sub
 
Last edited:

Pendrush

Well-Known Member
Licensed User
Longtime User
Great job mate.
Just got tested project on multiple layouts.
Working as expected with and without NavBar, in portrait and landscape on iPhone and on iPad.
 

Attachments

  • share.zip
    10.1 KB · Views: 576
Upvote 0

Albi

Active Member
Licensed User
Longtime User
i have one question about this now - when emailing picture using the mail composer, you have the option of choosing the file size, which doesn't happen when using this class. any idea how to change this class to give that option?

EDIT: my mistake, it does do that! woopwoop
 
Last edited:
Upvote 0

Pendrush

Well-Known Member
Licensed User
Longtime User
Now we have this warning (when click on Share) in iOS 9 beta 3

iPad error:
Copying updated assets files (19)
Application_Start
Application_Active
Attempt to add this NSLayoutConstraint to an engine in which it already exists. This can cause engine corruption. Break on void _NSLayoutConstraintRedundantAdd() to debug. This will be logged only once. This may break in the future.
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x16ec0030 V:[UIView:0x16ebe000(<=984)]>",
"<NSLayoutConstraint:0x16ebffa0 UIView:0x16ebe000.height == UIView:0x16eb7d10.height>",
"<NSLayoutConstraint:0x16ec0a10 _UIAlertControllerView:0x16ebd9b0.height == UIView:0x16eb7d10.height>",
"<NSLayoutConstraint:0x16df5ff0 _UIAlertControllerView:0x16ebd9b0.height == UIView:0x16d7ed30.height>",
"<NSLayoutConstraint:0x16edb430 'UIView-Encapsulated-Layout-Height' V:[UIView:0x16d7ed30(1024)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x16ec0030 V:[UIView:0x16ebe000(<=984)]>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
the behavior of the UICollectionViewFlowLayout is not defined because:
the item width must be less than the width of the UICollectionView minus the section insets left and right values, minus the content insets left and right values.
The relevant UICollectionViewFlowLayout instance is <_UIActivityGroupListViewLayout: 0x16eb4fc0>, and it is attached to <UICollectionView: 0x17a30200; frame = (0 0; 402 421); clipsToBounds = YES; opaque = NO; autoresize = W+H; gestureRecognizers = <NSArray: 0x16eb5910>; animations = { position=<CASpringAnimation: 0x16dd8c50>; bounds.origin=<CASpringAnimation: 0x16dd8e10>; bounds.size=<CASpringAnimation: 0x16dd8ea0>; position-2=<CASpringAnimation: 0x16de7930>; bounds.origin-2=<CASpringAnimation: 0x16eb4f20>; bounds.size-2=<CASpringAnimation: 0x16eb8970>; position-3=<CASpringAnimation: 0x16ed2200>; bounds.origin-3=<CASpringAnimation: 0x16ed2400>; bounds.size-3=<CASpringAnimation: 0x16ed2530>; position-4=<CASpringAnimation: 0x16edf140>; bounds.origin-4=<CASpringAnimation: 0x16edf360>; bounds.size-4=<CASpringAnimation: 0x16edf3f0>; }; layer = <CALayer: 0x16eb5820>; contentOffset: {0, 0}; contentSize: {748, 421}> collection view layout: <_UIActivityGroupListViewLayout: 0x16eb4fc0>.
Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.
the behavior of the UICollectionViewFlowLayout is not defined because:
the item width must be less than the width of the UICollectionView minus the section insets left and right values, minus the content insets left and right values.
The relevant UICollectionViewFlowLayout instance is <_UIActivityGroupListViewLayout: 0x16eb4fc0>, and it is attached to <UICollectionView: 0x17a30200; frame = (0 0; 402 421); clipsToBounds = YES; opaque = NO; autoresize = W+H; gestureRecognizers = <NSArray: 0x16eb5910>; animations = { position=<CASpringAnimation: 0x16dd8c50>; bounds.origin=<CASpringAnimation: 0x16dd8e10>; bounds.size=<CASpringAnimation: 0x16dd8ea0>; position-2=<CASpringAnimation: 0x16de7930>; bounds.origin-2=<CASpringAnimation: 0x16eb4f20>; bounds.size-2=<CASpringAnimation: 0x16eb8970>; position-3=<CASpringAnimation: 0x16ed2200>; bounds.origin-3=<CASpringAnimation: 0x16ed2400>; bounds.size-3=<CASpringAnimation: 0x16ed2530>; position-4=<CASpringAnimation: 0x16edf140>; bounds.origin-4=<CASpringAnimation: 0x16edf360>; bounds.size-4=<CASpringAnimation: 0x16edf3f0>; }; layer = <CALayer: 0x16eb5820>; contentOffset: {0, 0}; contentSize: {748, 421}> collection view layout: <_UIActivityGroupListViewLayout: 0x16eb4fc0>.
Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.
the behavior of the UICollectionViewFlowLayout is not defined because:
the item width must be less than the width of the UICollectionView minus the section insets left and right values, minus the content insets left and right values.
The relevant UICollectionViewFlowLayout instance is <_UIActivityGroupListViewLayout: 0x16eb4fc0>, and it is attached to <UICollectionView: 0x17a30200; frame = (0 0; 402 421); clipsToBounds = YES; opaque = NO; autoresize = W+H; gestureRecognizers = <NSArray: 0x16eb5910>; animations = { position=<CASpringAnimation: 0x16dd8c50>; bounds.origin=<CASpringAnimation: 0x16dd8e10>; bounds.size=<CASpringAnimation: 0x16dd8ea0>; position-2=<CASpringAnimation: 0x16de7930>; bounds.origin-2=<CASpringAnimation: 0x16eb4f20>; bounds.size-2=<CASpringAnimation: 0x16eb8970>; position-3=<CASpringAnimation: 0x16ed2200>; bounds.origin-3=<CASpringAnimation: 0x16ed2400>; bounds.size-3=<CASpringAnimation: 0x16ed2530>; position-4=<CASpringAnimation: 0x16edf140>; bounds.origin-4=<CASpringAnimation: 0x16edf360>; bounds.size-4=<CASpringAnimation: 0x16edf3f0>; }; layer = <CALayer: 0x16eb5820>; contentOffset: {0, 0}; contentSize: {748, 421}> collection view layout: <_UIActivityGroupListViewLayout: 0x16eb4fc0>.
Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.
Logging only once for UICollectionViewFlowLayout cache mismatched frame
UICollectionViewFlowLayout has cached frame mismatch for index path <NSIndexPath: 0x16edf780> {length = 2, path = 0 - 0} - cached value: {{0, 0}, {402, 155}}; expected value: {{-173, 0}, {748, 155}}
This is likely occurring because the flow layout subclass _UIActivityGroupListViewLayout is modifying attributes returned by UICollectionViewFlowLayout without copying them


iPhone error:
Attempt to add this NSLayoutConstraint to an engine in which it already exists. This can cause engine corruption. Break on void _NSLayoutConstraintRedundantAdd() to debug. This will be logged only once. This may break in the future.
 
Last edited:
Upvote 0

cloner7801

Active Member
Licensed User
Longtime User
I am using this code :
B4X:
Sub Process_Globals

  Private myPage As Page 'ignore
End Sub

#IF OBJC

//- (void)share2SocialMedia:(NSString *)txt :(NSString *)theurl :(NSString *)theimg :(UIView *)SBview :(float)nbHeight
- (void)share2SocialMedia:(NSString *)txt :(NSString *)theurl :(NSString *)theimg :(UIView *)SBview :(UINavigationBar *)nb
{

   CGFloat STATUS_BAR_HEIGHT = (
       [UIApplication sharedApplication].statusBarHidden ? 0 : (
         [UIApplication sharedApplication].statusBarFrame.size.height > 100 ?
         [UIApplication sharedApplication].statusBarFrame.size.width :
         [UIApplication sharedApplication].statusBarFrame.size.height
       )
   );

     //NSString *text = @"How to add Facebook and Twitter sharing to an iOS app";
     NSString *text = txt;
     //NSURL *url = [NSURL URLWithString:@"http://roadfiresoftware.com/2014/02/how-to-add-facebook-and-twitter-sharing-to-an-ios-app/"];
     NSURL *url = [NSURL URLWithString:theurl];
     //UIImage *image = [UIImage imageNamed:@"roadfire-icon-square-200"];
     UIImage *image;

     if([theimg hasPrefix:@"http://"] || [theimg hasPrefix:@"https://"] ) {
       image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:theimg]]];
     } else {
     if (theimg != nil && [theimg length] > 0) {
         image = [UIImage imageNamed:theimg];
       } else {
       image = nil;
     }
   }

     UIActivityViewController *controller =
     [[UIActivityViewController alloc]
     initWithActivityItems:@[text, url, image]
     applicationActivities:nil];

     controller.excludedActivityTypes = @[UIActivityTypePostToWeibo,
     UIActivityTypePrint,
     UIActivityTypeAssignToContact,
     UIActivityTypeSaveToCameraRoll,
     UIActivityTypeAddToReadingList,
     UIActivityTypePostToFlickr,
     UIActivityTypePostToVimeo,
     UIActivityTypePostToTencentWeibo];

     [controller setCompletionHandler:^(NSString*activityType, BOOL completed) {

       // Raise the event for B4i
       if (completed) {
       [self.bi raiseEvent:nil event:@"activity_completed::" params:@[@((BOOL)completed),(activityType)]];
       } else {

         NSString *activity = @"";
       [self.bi raiseEvent:nil event:@"activity_completed::" params:@[@((BOOL)completed),(activity)]];
       }
     }];

     //if iPhone
     if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
     [(self._mypage).object presentViewController:controller animated:YES completion:nil];
   } else { //if iPad

       UIPopoverController *popup = [[UIPopoverController alloc] initWithContentViewController:controller];
     UIWindow *window = [[UIApplication sharedApplication] keyWindow];
     UIView *topView = window.rootViewController.view;
     CGFloat extra = 0;
  
     if (nb != nil) {
       extra += nb.frame.size.height;
     }
  
     if ([UIApplication sharedApplication].statusBarHidden == NO)
     {
       extra += STATUS_BAR_HEIGHT;
     }
     //[popup presentPopoverFromRect:CGRectMake(SCREEN_WIDTH/2, SCREEN_HEIGHT/4, 0, 0)inView:topView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
     //[popup presentPopoverFromRect:CGRectMake(SBview.Left + SBview.Width/2, SBview.Top+SBview.Height,0,SBview.Height)inView:topView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
       [popup presentPopoverFromRect:CGRectMake(SBview.Left + SBview.Width/2, SBview.Top+SBview.Height+extra, 0, 0)inView:topView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
     }
}

#End If

Sub activity_completed(status As Boolean, T As String)

'If Main.DEBUG Then
'    Utils.Log_("onSharingDone: Status = " & status & " - Type: " & T & " - Will look for callback: ShareModule_SharingCompleted in " & myPage.Title)
'End If

  'If SubExists(myPage, "ShareModule_SharingCompleted", 2) = True Then
   '  CallSub3(myPage, "ShareModule_SharingCompleted", status, T)
  'End If

End Sub

Sub ShareToSocialMedia(p As Page, txt As String, theURL As String, imageFileOrURL As String, shareButton As View)

    Dim v As View = shareButton

    myPage = p
    Dim NativeMe As NativeObject = Me
    Dim NativeMe2 As NativeObject = Main.NavControl
    Dim NativeMe3 As NativeObject = NativeMe2.GetField("navigationBar")
    Dim nb As Object = NativeMe3

    If Main.NavControl.NavigationBarVisible Then
        NativeMe.RunMethod("share2SocialMedia:::::", Array As Object(txt, theURL, imageFileOrURL, v, nb))
    Else
        NativeMe.RunMethod("share2SocialMedia:::::", Array As Object(txt, theURL, imageFileOrURL, v, Null))
    End If

End Sub
When click on copy its copy the image , I want to copy text what should I do?
 
Upvote 0

jazzzzzzz

Active Member
Licensed User
Longtime User
Great job mate.
Just got tested project on multiple layouts.
Working as expected with and without NavBar, in portrait and landscape on iPhone and on iPad.
I have tried to run your code on my iPhone 6S with iOS 9.3.2 but only text is shared,Image is not at all sharing.
I haven't changed any code in your project
 
Upvote 0

Descartex

Well-Known Member
Licensed User
Longtime User
Hi,
I'm trying to integrate this function to my app, but i can't make work the sample with local file.
It raises this error:
*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[2]
And the code i'm trying to run is:
B4X:
Dim strImagePath As String
strImagePath = File.DirDocuments & "temp.png"
Log(strImagePath)
modShare.ShareToSocialMedia(pg, "File Shared successfully", "", strImagePath, Sender)

If I run the sample with Online Image, it runs perfectly.
Thanks in advance.
 
Upvote 0
Top