Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
ShareExtend
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
李增强
ShareExtend
Commits
7d6ac863
Commit
7d6ac863
authored
Mar 25, 2019
by
zhouteng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
修复android平台视频分享到微信失败的问题
parent
401f3580
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
235 additions
and
113 deletions
+235
-113
android/src/main/AndroidManifest.xml
android/src/main/AndroidManifest.xml
+1
-1
android/src/main/java/com/zt/shareextend/ShareExtendPlugin.java
...d/src/main/java/com/zt/shareextend/ShareExtendPlugin.java
+13
-25
android/src/main/java/com/zt/shareextend/ShareUtils.java
android/src/main/java/com/zt/shareextend/ShareUtils.java
+129
-0
example/ios/Runner.xcodeproj/project.pbxproj
example/ios/Runner.xcodeproj/project.pbxproj
+5
-3
example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
...s/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+1
-3
example/lib/main.dart
example/lib/main.dart
+34
-23
ios/Classes/ShareExtendPlugin.m
ios/Classes/ShareExtendPlugin.m
+52
-58
No files found.
android/src/main/AndroidManifest.xml
View file @
7d6ac863
...
...
@@ -7,7 +7,7 @@
<provider
android:name=
"androidx.core.content.FileProvider"
android:authorities=
"
com.zt.shareextend
.fileprovider"
android:authorities=
"
${applicationId}
.fileprovider"
android:exported=
"false"
android:grantUriPermissions=
"true"
>
<meta-data
...
...
android/src/main/java/com/zt/shareextend/ShareExtendPlugin.java
View file @
7d6ac863
package
com.zt.shareextend
;
import
io.flutter.plugin.common.MethodCall
;
import
io.flutter.plugin.common.MethodChannel
;
import
io.flutter.plugin.common.PluginRegistry
;
import
io.flutter.plugin.common.PluginRegistry.Registrar
;
import
android.Manifest
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.content.pm.PackageManager
;
import
android.net.Uri
;
import
android.os.Build
;
import
android.os.Environment
;
import
androidx.core.app.ActivityCompat
;
import
androidx.core.content.ContextCompat
;
import
androidx.core.content.FileProvider
;
import
java.io.File
;
import
java.util.Map
;
import
androidx.core.app.ActivityCompat
;
import
androidx.core.content.ContextCompat
;
import
io.flutter.plugin.common.MethodCall
;
import
io.flutter.plugin.common.MethodChannel
;
import
io.flutter.plugin.common.PluginRegistry
;
import
io.flutter.plugin.common.PluginRegistry.Registrar
;
/**
* Plugin method host for presenting a share sheet via Intent
*/
public
class
ShareExtendPlugin
implements
MethodChannel
.
MethodCallHandler
,
PluginRegistry
.
RequestPermissionsResultListener
{
/// the authorities for FileProvider
private
static
final
String
authorities
=
"com.zt.shareextend.fileprovider"
;
private
static
final
int
CODE_ASK_PERMISSION
=
100
;
private
static
final
String
CHANNEL
=
"share_extend"
;
...
...
@@ -84,12 +78,14 @@ public class ShareExtendPlugin implements MethodChannel.MethodCallHandler, Plugi
}
File
f
=
new
File
(
text
);
Uri
uri
=
getUriForFile
(
mRegistrar
.
context
(),
f
);
if
(
"file"
.
equals
(
type
))
{
shareIntent
.
setType
(
"application/*"
);
}
Uri
uri
=
ShareUtils
.
getUriForFile
(
mRegistrar
.
context
(),
f
);
if
(
"image"
.
equals
(
type
))
{
shareIntent
.
setType
(
"image/*"
);
}
else
if
(
"video"
.
equals
(
type
))
{
shareIntent
.
setType
(
"video/*"
);
}
else
{
shareIntent
.
setType
(
"application/*"
);
}
shareIntent
.
putExtra
(
Intent
.
EXTRA_STREAM
,
uri
);
}
...
...
@@ -127,12 +123,4 @@ public class ShareExtendPlugin implements MethodChannel.MethodCallHandler, Plugi
}
return
false
;
}
private
static
Uri
getUriForFile
(
Context
context
,
File
file
)
{
if
(
Build
.
VERSION
.
SDK_INT
>=
24
)
{
return
FileProvider
.
getUriForFile
(
context
,
authorities
,
file
);
}
else
{
return
Uri
.
fromFile
(
file
);
}
}
}
android/src/main/java/com/zt/shareextend/ShareUtils.java
0 → 100644
View file @
7d6ac863
package
com.zt.shareextend
;
import
android.content.ContentResolver
;
import
android.content.ContentValues
;
import
android.content.Context
;
import
android.database.Cursor
;
import
android.net.Uri
;
import
android.os.Build
;
import
android.provider.MediaStore
;
import
android.text.TextUtils
;
import
java.io.File
;
import
androidx.core.content.FileProvider
;
public
class
ShareUtils
{
/// get the uri for file
public
static
Uri
getUriForFile
(
Context
context
,
File
file
)
{
String
authorities
=
context
.
getPackageName
()
+
".fileprovider"
;
Uri
uri
;
// 低版本直接用 Uri.fromFile
if
(
Build
.
VERSION
.
SDK_INT
<
Build
.
VERSION_CODES
.
N
)
{
uri
=
Uri
.
fromFile
(
file
);
}
else
{
// 使用 FileProvider 会在某些 app 下不支持(在使用FileProvider 方式情况下QQ不能支持图片、视频分享,微信不支持视频分享)
uri
=
FileProvider
.
getUriForFile
(
context
,
authorities
,
file
);
ContentResolver
cR
=
context
.
getContentResolver
();
if
(
uri
!=
null
&&
!
TextUtils
.
isEmpty
(
uri
.
toString
()))
{
String
fileType
=
cR
.
getType
(
uri
);
// 使用 MediaStore 的 content:// 而不是自己 FileProvider 提供的uri,不然有些app无法适配
if
(!
TextUtils
.
isEmpty
(
fileType
))
{
if
(
fileType
.
contains
(
"video/"
))
{
uri
=
getVideoContentUri
(
context
,
file
);
}
else
if
(
fileType
.
contains
(
"image/"
))
{
uri
=
getImageContentUri
(
context
,
file
);
}
else
if
(
fileType
.
contains
(
"audio/"
))
{
uri
=
getAudioContentUri
(
context
,
file
);
}
}
}
}
return
uri
;
}
/**
* Gets the content:// URI from the given corresponding path to a file
*
* @param context
* @param imageFile
* @return content Uri
*/
public
static
Uri
getImageContentUri
(
Context
context
,
File
imageFile
)
{
String
filePath
=
imageFile
.
getAbsolutePath
();
Cursor
cursor
=
context
.
getContentResolver
().
query
(
MediaStore
.
Images
.
Media
.
EXTERNAL_CONTENT_URI
,
new
String
[]{
MediaStore
.
Images
.
Media
.
_ID
},
MediaStore
.
Images
.
Media
.
DATA
+
"=? "
,
new
String
[]{
filePath
},
null
);
if
(
cursor
!=
null
&&
cursor
.
moveToFirst
())
{
int
id
=
cursor
.
getInt
(
cursor
.
getColumnIndex
(
MediaStore
.
MediaColumns
.
_ID
));
Uri
baseUri
=
Uri
.
parse
(
"content://media/external/images/media"
);
return
Uri
.
withAppendedPath
(
baseUri
,
""
+
id
);
}
else
{
if
(
imageFile
.
exists
())
{
ContentValues
values
=
new
ContentValues
();
values
.
put
(
MediaStore
.
Images
.
Media
.
DATA
,
filePath
);
return
context
.
getContentResolver
().
insert
(
MediaStore
.
Images
.
Media
.
EXTERNAL_CONTENT_URI
,
values
);
}
else
{
return
null
;
}
}
}
/**
* Gets the content:// URI from the given corresponding path to a file
*
* @param context
* @param videoFile
* @return content Uri
*/
public
static
Uri
getVideoContentUri
(
Context
context
,
File
videoFile
)
{
String
filePath
=
videoFile
.
getAbsolutePath
();
Cursor
cursor
=
context
.
getContentResolver
().
query
(
MediaStore
.
Video
.
Media
.
EXTERNAL_CONTENT_URI
,
new
String
[]{
MediaStore
.
Video
.
Media
.
_ID
},
MediaStore
.
Video
.
Media
.
DATA
+
"=? "
,
new
String
[]{
filePath
},
null
);
if
(
cursor
!=
null
&&
cursor
.
moveToFirst
())
{
int
id
=
cursor
.
getInt
(
cursor
.
getColumnIndex
(
MediaStore
.
MediaColumns
.
_ID
));
Uri
baseUri
=
Uri
.
parse
(
"content://media/external/video/media"
);
return
Uri
.
withAppendedPath
(
baseUri
,
""
+
id
);
}
else
{
if
(
videoFile
.
exists
())
{
ContentValues
values
=
new
ContentValues
();
values
.
put
(
MediaStore
.
Video
.
Media
.
DATA
,
filePath
);
return
context
.
getContentResolver
().
insert
(
MediaStore
.
Video
.
Media
.
EXTERNAL_CONTENT_URI
,
values
);
}
else
{
return
null
;
}
}
}
/**
* Gets the content:// URI from the given corresponding path to a file
*
* @param context
* @param audioFile
* @return content Uri
*/
public
static
Uri
getAudioContentUri
(
Context
context
,
File
audioFile
)
{
String
filePath
=
audioFile
.
getAbsolutePath
();
Cursor
cursor
=
context
.
getContentResolver
().
query
(
MediaStore
.
Audio
.
Media
.
EXTERNAL_CONTENT_URI
,
new
String
[]{
MediaStore
.
Audio
.
Media
.
_ID
},
MediaStore
.
Audio
.
Media
.
DATA
+
"=? "
,
new
String
[]{
filePath
},
null
);
if
(
cursor
!=
null
&&
cursor
.
moveToFirst
())
{
int
id
=
cursor
.
getInt
(
cursor
.
getColumnIndex
(
MediaStore
.
MediaColumns
.
_ID
));
Uri
baseUri
=
Uri
.
parse
(
"content://media/external/audio/media"
);
return
Uri
.
withAppendedPath
(
baseUri
,
""
+
id
);
}
else
{
if
(
audioFile
.
exists
())
{
ContentValues
values
=
new
ContentValues
();
values
.
put
(
MediaStore
.
Audio
.
Media
.
DATA
,
filePath
);
return
context
.
getContentResolver
().
insert
(
MediaStore
.
Audio
.
Media
.
EXTERNAL_CONTENT_URI
,
values
);
}
else
{
return
null
;
}
}
}
}
example/ios/Runner.xcodeproj/project.pbxproj
View file @
7d6ac863
...
...
@@ -15,7 +15,6 @@
3B80C3951E831B6300D905FE
/* App.framework in Embed Frameworks */
=
{
isa
=
PBXBuildFile
;
fileRef
=
3B80C3931E831B6300D905FE
/* App.framework */
;
settings
=
{
ATTRIBUTES
=
(
CodeSignOnCopy
,
RemoveHeadersOnCopy
,
);
};
};
9705A1C61CF904A100538489
/* Flutter.framework in Frameworks */
=
{
isa
=
PBXBuildFile
;
fileRef
=
9740EEBA1CF902C7004384FC
/* Flutter.framework */
;
};
9705A1C71CF904A300538489
/* Flutter.framework in Embed Frameworks */
=
{
isa
=
PBXBuildFile
;
fileRef
=
9740EEBA1CF902C7004384FC
/* Flutter.framework */
;
settings
=
{
ATTRIBUTES
=
(
CodeSignOnCopy
,
RemoveHeadersOnCopy
,
);
};
};
9740EEB41CF90195004384FC
/* Debug.xcconfig in Resources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
9740EEB21CF90195004384FC
/* Debug.xcconfig */
;
};
978B8F6F1D3862AE00F588F7
/* AppDelegate.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
7AFFD8EE1D35381100E5BB4D
/* AppDelegate.m */
;
};
97C146F31CF9000F007C117D
/* main.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
97C146F21CF9000F007C117D
/* main.m */
;
};
97C146FC1CF9000F007C117D
/* Main.storyboard in Resources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
97C146FA1CF9000F007C117D
/* Main.storyboard */
;
};
...
...
@@ -176,7 +175,7 @@
97C146E61CF9000F007C117D
/* Project object */
=
{
isa
=
PBXProject
;
attributes
=
{
LastUpgradeCheck
=
09
10
;
LastUpgradeCheck
=
10
10
;
ORGANIZATIONNAME
=
"The Chromium Authors"
;
TargetAttributes
=
{
97C146ED1CF9000F007C117D
=
{
...
...
@@ -209,7 +208,6 @@
files
=
(
97C147011CF9000F007C117D
/* LaunchScreen.storyboard in Resources */
,
3B3967161E833CAA004F5970
/* AppFrameworkInfo.plist in Resources */
,
9740EEB41CF90195004384FC
/* Debug.xcconfig in Resources */
,
97C146FE1CF9000F007C117D
/* Assets.xcassets in Resources */
,
2D5378261FAA1A9400D5DBA9
/* flutter_assets in Resources */
,
97C146FC1CF9000F007C117D
/* Main.storyboard in Resources */
,
...
...
@@ -332,12 +330,14 @@
CLANG_WARN_BOOL_CONVERSION
=
YES
;
CLANG_WARN_COMMA
=
YES
;
CLANG_WARN_CONSTANT_CONVERSION
=
YES
;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS
=
YES
;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE
=
YES_ERROR
;
CLANG_WARN_EMPTY_BODY
=
YES
;
CLANG_WARN_ENUM_CONVERSION
=
YES
;
CLANG_WARN_INFINITE_RECURSION
=
YES
;
CLANG_WARN_INT_CONVERSION
=
YES
;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION
=
YES
;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF
=
YES
;
CLANG_WARN_OBJC_LITERAL_CONVERSION
=
YES
;
CLANG_WARN_OBJC_ROOT_CLASS
=
YES_ERROR
;
CLANG_WARN_RANGE_LOOP_ANALYSIS
=
YES
;
...
...
@@ -386,12 +386,14 @@
CLANG_WARN_BOOL_CONVERSION
=
YES
;
CLANG_WARN_COMMA
=
YES
;
CLANG_WARN_CONSTANT_CONVERSION
=
YES
;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS
=
YES
;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE
=
YES_ERROR
;
CLANG_WARN_EMPTY_BODY
=
YES
;
CLANG_WARN_ENUM_CONVERSION
=
YES
;
CLANG_WARN_INFINITE_RECURSION
=
YES
;
CLANG_WARN_INT_CONVERSION
=
YES
;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION
=
YES
;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF
=
YES
;
CLANG_WARN_OBJC_LITERAL_CONVERSION
=
YES
;
CLANG_WARN_OBJC_ROOT_CLASS
=
YES_ERROR
;
CLANG_WARN_RANGE_LOOP_ANALYSIS
=
YES
;
...
...
example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
View file @
7d6ac863
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion =
"
09
10"
LastUpgradeVersion =
"
10
10"
version =
"1.3"
>
<BuildAction
parallelizeBuildables =
"YES"
...
...
@@ -26,7 +26,6 @@
buildConfiguration =
"Debug"
selectedDebuggerIdentifier =
"Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier =
"Xcode.DebuggerFoundation.Launcher.LLDB"
language =
""
shouldUseLaunchSchemeArgsEnv =
"YES"
>
<Testables>
</Testables>
...
...
@@ -46,7 +45,6 @@
buildConfiguration =
"Debug"
selectedDebuggerIdentifier =
"Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier =
"Xcode.DebuggerFoundation.Launcher.LLDB"
language =
""
launchStyle =
"0"
useCustomWorkingDirectory =
"NO"
ignoresPersistentStateOnLaunch =
"NO"
...
...
example/lib/main.dart
View file @
7d6ac863
...
...
@@ -25,31 +25,42 @@ class _MyAppState extends State<MyApp> {
appBar:
new
AppBar
(
title:
const
Text
(
'Plugin example app'
),
),
body:
new
Center
(
body:
Container
(
child:
new
Center
(
child:
new
Column
(
children:
<
Widget
>[
new
RaisedButton
(
onPressed:
()
{
ShareExtend
.
share
(
"share text"
,
"text"
);
},
child:
new
Text
(
"share text"
),
children:
<
Widget
>[
new
RaisedButton
(
onPressed:
()
{
ShareExtend
.
share
(
"share text"
,
"text"
);
},
child:
new
Text
(
"share text"
),
),
new
RaisedButton
(
onPressed:
()
async
{
File
f
=
await
ImagePicker
.
pickImage
(
source
:
ImageSource
.
gallery
);
ShareExtend
.
share
(
f
.
path
,
"image"
);
},
child:
new
Text
(
"share image"
),
),
new
RaisedButton
(
onPressed:
()
async
{
File
f
=
await
ImagePicker
.
pickVideo
(
source
:
ImageSource
.
gallery
);
ShareExtend
.
share
(
f
.
path
,
"video"
);
},
child:
new
Text
(
"share video"
),
),
new
RaisedButton
(
onPressed:
()
{
_shareApplicationDocumentsFile
();
},
child:
new
Text
(
"share file"
),
),
],
),
new
RaisedButton
(
onPressed:
()
async
{
File
f
=
await
ImagePicker
.
pickImage
(
source
:
ImageSource
.
gallery
);
ShareExtend
.
share
(
f
.
path
,
"image"
);
},
child:
new
Text
(
"share image"
),
),
new
RaisedButton
(
onPressed:
()
{
_shareApplicationDocumentsFile
();
},
child:
new
Text
(
"share file"
),
),
],
)),
),
),
),
);
}
...
...
ios/Classes/ShareExtendPlugin.m
View file @
7d6ac863
#import "ShareExtendPlugin.h"
@implementation
FLTShareExtendPlugin
+
(
void
)
registerWithRegistrar
:(
NSObject
<
FlutterPluginRegistrar
>*
)
registrar
{
FlutterMethodChannel
*
shareChannel
=
[
FlutterMethodChannel
methodChannelWithName:
@"share_extend"
binaryMessenger:
[
registrar
messenger
]];
[
shareChannel
setMethodCallHandler
:
^
(
FlutterMethodCall
*
call
,
FlutterResult
result
)
{
if
([
@"share"
isEqualToString
:
call
.
method
])
{
NSDictionary
*
arguments
=
[
call
arguments
];
NSString
*
shareText
=
arguments
[
@"text"
];
NSString
*
shareType
=
arguments
[
@"type"
];
if
(
shareText
.
length
==
0
)
{
result
(
[
FlutterError
errorWithCode
:
@"error"
message
:
@"Non-empty text expected"
details
:
nil
]);
return
;
}
NSNumber
*
originX
=
arguments
[
@"originX"
];
NSNumber
*
originY
=
arguments
[
@"originY"
];
NSNumber
*
originWidth
=
arguments
[
@"originWidth"
];
NSNumber
*
originHeight
=
arguments
[
@"originHeight"
];
CGRect
originRect
;
if
(
originX
!=
nil
&&
originY
!=
nil
&&
originWidth
!=
nil
&&
originHeight
!=
nil
)
{
originRect
=
CGRectMake
([
originX
doubleValue
],
[
originY
doubleValue
],
[
originWidth
doubleValue
],
[
originHeight
doubleValue
]);
}
if
([
shareType
isEqualToString
:
@"text"
])
{
[
self
share
:
shareText
withController:
[
UIApplication
sharedApplication
].
keyWindow
.
rootViewController
atSource:
originRect
];
result
(
nil
);
}
else
if
([
shareType
isEqualToString
:
@"file"
])
{
NSURL
*
url
=
[
NSURL
fileURLWithPath
:
shareText
];
[
self
share
:
url
withController:
[
UIApplication
sharedApplication
].
keyWindow
.
rootViewController
atSource:
originRect
];
result
(
nil
);
}
else
if
([
shareType
isEqualToString
:
@"image"
])
{
UIImage
*
image
=
[
UIImage
imageWithContentsOfFile
:
shareText
];
[
self
share
:
image
withController:
[
UIApplication
sharedApplication
].
keyWindow
.
rootViewController
atSource:
originRect
];
+
(
void
)
registerWithRegistrar
:(
NSObject
<
FlutterPluginRegistrar
>*
)
registrar
{
FlutterMethodChannel
*
shareChannel
=
[
FlutterMethodChannel
methodChannelWithName:
@"share_extend"
binaryMessenger:
[
registrar
messenger
]];
[
shareChannel
setMethodCallHandler
:
^
(
FlutterMethodCall
*
call
,
FlutterResult
result
)
{
if
([
@"share"
isEqualToString
:
call
.
method
])
{
NSDictionary
*
arguments
=
[
call
arguments
];
NSString
*
shareText
=
arguments
[
@"text"
];
NSString
*
shareType
=
arguments
[
@"type"
];
if
(
shareText
.
length
==
0
)
{
result
(
[
FlutterError
errorWithCode
:
@"error"
message
:
@"Non-empty text expected"
details
:
nil
]);
return
;
}
NSNumber
*
originX
=
arguments
[
@"originX"
];
NSNumber
*
originY
=
arguments
[
@"originY"
];
NSNumber
*
originWidth
=
arguments
[
@"originWidth"
];
NSNumber
*
originHeight
=
arguments
[
@"originHeight"
];
CGRect
originRect
;
if
(
originX
!=
nil
&&
originY
!=
nil
&&
originWidth
!=
nil
&&
originHeight
!=
nil
)
{
originRect
=
CGRectMake
([
originX
doubleValue
],
[
originY
doubleValue
],
[
originWidth
doubleValue
],
[
originHeight
doubleValue
]);
}
if
([
shareType
isEqualToString
:
@"text"
])
{
[
self
share
:
shareText
atSource
:
originRect
];
result
(
nil
);
}
else
if
([
shareType
isEqualToString
:
@"image"
])
{
UIImage
*
image
=
[
UIImage
imageWithContentsOfFile
:
shareText
];
[
self
share
:
image
atSource
:
originRect
];
}
else
{
NSURL
*
url
=
[
NSURL
fileURLWithPath
:
shareText
];
[
self
share
:
url
atSource
:
originRect
];
result
(
nil
);
}
}
else
{
result
(
FlutterMethodNotImplemented
);
}
}
else
{
result
(
FlutterMethodNotImplemented
);
}
}];
}];
}
+
(
void
)
share
:(
id
)
sharedItems
withController
:(
UIViewController
*
)
controller
atSource
:(
CGRect
)
origin
{
UIActivityViewController
*
activityViewController
=
[[
UIActivityViewController
alloc
]
initWithActivityItems
:@[
sharedItems
]
applicationActivities:
nil
];
activityViewController
.
popoverPresentationController
.
sourceView
=
controller
.
view
;
if
(
!
CGRectIsEmpty
(
origin
))
{
activityViewController
.
popoverPresentationController
.
sourceRect
=
origin
;
}
[
controller
presentViewController
:
activityViewController
animated
:
YES
completion
:
nil
];
+
(
void
)
share
:(
id
)
sharedItems
atSource
:(
CGRect
)
origin
{
UIActivityViewController
*
activityViewController
=
[[
UIActivityViewController
alloc
]
initWithActivityItems
:@[
sharedItems
]
applicationActivities
:
nil
];
UIViewController
*
controller
=
[
UIApplication
sharedApplication
].
keyWindow
.
rootViewController
;
activityViewController
.
popoverPresentationController
.
sourceView
=
controller
.
view
;
if
(
!
CGRectIsEmpty
(
origin
))
{
activityViewController
.
popoverPresentationController
.
sourceRect
=
origin
;
}
[
controller
presentViewController
:
activityViewController
animated
:
YES
completion
:
nil
];
}
@end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment