Android分享转发功能
祝君圆梦 人气:0导读:
之前刚学安卓时,写过一篇“Android调用系统shareAPI实现分享转发功能”的文章,随着安卓版本的迭代更新以及其他APP的优化,安卓的这个shareAPI好像失效了,不怎么好使,已经获取不到有分享功能的APP列表,点击分享也会直接崩溃。并不是说我之前那篇文章的代码有错,只能说是时代有了变化,旧的方法已经不能满足新的需求
最近开发一个收款APP,想把分享功能加入进去,然后发现旧的方法已经不行,这就难过了,网上一些大佬建议用第三方APP自带的分享SDK,但是我觉得用第三方的SDK太麻烦了,每个 APP都要申请接口账号和接口密钥,即便是使用其他人封装好的分享框架,也是需要去申请账号密钥的,一点也不方便,还是喜欢安卓原生态写法,简单便捷、一劳永逸。
经过我几番研究,最终完美实现了,效果图如下:
一、xml布局文件
1、res/layout目录下创建share_dialog.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/shape_dialog_bg" android:orientation="vertical" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:text="分享到..." /> <HorizontalScrollView android:layout_width="match_parent" android:layout_height="wrap_content" android:scrollbars="none" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" > <GridView android:id="@+id/sharePopupWindow_gridView" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="none" /> </LinearLayout> </HorizontalScrollView> <View android:layout_width="match_parent" android:layout_height="1px" android:alpha="0.3" android:background="#666" /> <TextView android:id="@+id/sharePopupWindow_close" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:padding="20dp" android:text="取消" android:textSize="16sp" /> </LinearLayout>
2、res/layout目录下创建appinfo_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="vertical" android:paddingBottom="8dp" android:paddingLeft="16dp" android:paddingRight="16dp" android:paddingTop="8dp"> <ImageView android:id="@+id/appinfo_item_icon" android:layout_width="48dp" android:layout_height="48dp" android:scaleType="centerCrop" android:src="@drawable/logo"/> <TextView android:id="@+id/appinfo_item_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="2dp" android:ellipsize="end" android:singleLine="true" android:textSize="12sp" android:text="分享到……"/> </LinearLayout>
3、在res/values/styles.xml 中,添加以下代码,用来实现弹出窗背景效果:
<style name="circleDialog" parent="android:style/Theme.Dialog"> <!-- 背景透明,设置圆角对话框必须设置背景透明,否则四角会有背景色小块--> <item name="android:windowBackground">@android:color/transparent</item> <!-- 没有标题 --> <item name="android:windowNoTitle">true</item> <!-- 背景模糊 --> <item name="android:backgroundDimEnabled">true</item> </style>
二、创建一个实体类 AppInfo.java,用来保存应用信息
package net.zy13.skhelper.entity; import android.graphics.drawable.Drawable; /** * APP信息实体类 */ public class AppInfo { private String appName; private String packageName; private String versionName; private int versionCode; private String launchClassName; private Drawable appIcon; public String getAppName() { return appName; } public void setAppName(String appName) { this.appName = appName; } public String getPackageName() { return packageName; } public void setPackageName(String packageName) { this.packageName = packageName; } public String getVersionName() { return versionName; } public void setVersionName(String versionName) { this.versionName = versionName; } public int getVersionCode() { return versionCode; } public void setVersionCode(int versionCode) { this.versionCode = versionCode; } public String getLaunchClassName() { return launchClassName; } public void setLaunchClassName(String launchClassName) { this.launchClassName = launchClassName; } public Drawable getAppIcon() { return appIcon; } public void setAppIcon(Drawable appIcon) { this.appIcon = appIcon; } }
三、重写PopupWindow控件SharePopupWindow.java,自定义分享的弹窗
package net.zy13.skhelper.view; import java.io.File; import java.util.List; import android.app.ActionBar.LayoutParams; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.GridView; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.TextView; import androidx.core.content.FileProvider; import net.zy13.skhelper.R; import net.zy13.skhelper.adapter.AppInfoAdapter; import net.zy13.skhelper.entity.AppInfo; import net.zy13.skhelper.utils.LogUtil; import net.zy13.skhelper.utils.MapTable; import net.zy13.skhelper.utils.ShareUtil; public class SharePopupWindow extends PopupWindow { //每行显示多少个 private static final int NUM = 5; private View mMenuView; private GridView mGridView; private TextView mTextViewClose; private AppInfoAdapter mAdapter; private List<AppInfo> mAppinfoList; private String imgpath; private String shareTitle; private String shareContent; public void setImgpath(String imgpath) { this.imgpath = imgpath; } public void setShareTitle(String shareTitle) { this.shareTitle = shareTitle; } public void setShareContent(String shareContent) { this.shareContent = shareContent; } /** * 构造函数 * @param context */ public SharePopupWindow(final Context context) { super(context); LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); mMenuView = inflater.inflate(R.layout.share_dialog, null); //获取控件 mGridView=(GridView) mMenuView.findViewById(R.id.sharePopupWindow_gridView); mTextViewClose=(TextView) mMenuView.findViewById(R.id.sharePopupWindow_close); //获取所有的非系统应用 mAppinfoList = ShareUtil.getAllApps(context); //适配GridView mAdapter=new AppInfoAdapter(context, mAppinfoList); mGridView.setAdapter(mAdapter); //修改GridView changeGridView(context); mGridView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // TODO Auto-generated method stub //使用其他APP打开文件 Intent intent = new Intent(); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); intent.setAction(Intent.ACTION_VIEW); //LogUtil.debug("图片地址:"+imgpath); //我这里分享的是图片,如果你要分享链接和文本,可以在这里自行发挥 Uri uri = FileProvider.getUriForFile(context, "fileprovider", new File(imgpath)); intent.setDataAndType(uri, MapTable.getMIMEType(imgpath)); context.startActivity(intent); } }); //取消按钮 mTextViewClose.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub dismiss(); } }); //设置SelectPicPopupWindow的View this.setContentView(mMenuView); //设置SelectPicPopupWindow弹出窗体的宽 this.setWidth(LayoutParams.FILL_PARENT); //设置SelectPicPopupWindow弹出窗体的高 this.setHeight(LayoutParams.WRAP_CONTENT); //设置SelectPicPopupWindow弹出窗体可点击 this.setFocusable(true); //设置窗口外也能点击(点击外面时,窗口可以关闭) this.setOutsideTouchable(true); //设置SelectPicPopupWindow弹出窗体动画效果 this.setAnimationStyle(R.style.circleDialog); //实例化一个ColorDrawable颜色为半透明 ColorDrawable dw = new ColorDrawable(0x00000000); //设置SelectPicPopupWindow弹出窗体的背景 this.setBackgroundDrawable(dw); } /** * 将GridView改成单行横向布局 */ private void changeGridView(Context context) { // item宽度 int itemWidth = dip2px(context, 90); // item之间的间隔 int itemPaddingH = dip2px(context, 1); //计算一共显示多少行; int size = mAppinfoList.size(); //int row=(size<=NUM) ? 1 :( (size%NUM>0) ? size/NUM+1 : size/NUM ); //每行真正显示多少个 int rowitem = (size<NUM)?size:NUM; // 计算GridView宽度 int gridviewWidth = rowitem * (itemWidth + itemPaddingH); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( gridviewWidth, LinearLayout.LayoutParams.MATCH_PARENT); mGridView.setLayoutParams(params); mGridView.setColumnWidth(itemWidth); mGridView.setHorizontalSpacing(itemPaddingH); mGridView.setStretchMode(GridView.NO_STRETCH); mGridView.setNumColumns(rowitem); } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) * @param context 上下文 * @param dpValue dp值 * @return px值 */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } }
四、使用provider
1、在清单文件AndroidManifest.xml的<application>标签内添加provider
<provider android:name="androidx.core.content.FileProvider" android:authorities="fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths"/> </provider>
注意:要与activity标签同级
2、在res/xml目录添加filepaths.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 1、name对应的属性值,开发者可以自由定义; 2、path对应的属性值,当前external-path标签下的相对路径 --> <!--1、对应内部内存卡根目录:Context.getFileDir()--> <files-path name="int_root" path="/" /> <!--2、对应应用默认缓存根目录:Context.getCacheDir()--> <cache-path name="app_cache" path="/" /> <!--3、对应外部内存卡根目录:Environment.getExternalStorageDirectory()--> <external-path name="ext_root" path="Documents/" /> <!--4、对应外部内存卡根目录下的APP公共目录:Context.getExternalFileDir(Environment.DIRECTORY_PICTURES)--> <external-files-path name="ext_pub" path="/" /> <!--5、对应外部内存卡根目录下的APP缓存目录:Context.getExternalCacheDir()--> <external-cache-path name="ext_cache" path="/" /> </paths>
五、写一个工具类
ShareUtil.java
package net.zy13.skhelper.utils; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import net.zy13.skhelper.MainApplication; import net.zy13.skhelper.entity.AppInfo; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class ShareUtil { /** * 查询手机内所有的应用列表 * @param context * @return */ public static List<AppInfo> getAllApps(Context context) { List<AppInfo> appList = new ArrayList<AppInfo>(); PackageManager pm=context.getPackageManager(); List<PackageInfo> packages = pm.getInstalledPackages(0); for (int i = 0;i< packages.size();i++) { PackageInfo packageInfo = packages.get(i); AppInfo tmpInfo = new AppInfo(); tmpInfo.setAppName(packageInfo.applicationInfo.loadLabel(pm).toString()); tmpInfo.setPackageName(packageInfo.packageName); tmpInfo.setVersionName(packageInfo.versionName); tmpInfo.setVersionCode(packageInfo.versionCode); tmpInfo.setAppIcon(packageInfo.applicationInfo.loadIcon(pm)); //如果非系统应用,则添加至appList if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { //排除当前应用(替换成你的应用包名即可) if(!packageInfo.packageName.equals("net.zy13.skhelper")) { appList.add(tmpInfo); } } } return appList; } /** * 保存图片到缓存里 * @param bitmap * @return */ public static String SaveTitmapToCache(Bitmap bitmap){ // 默认保存在应用缓存目录里 Context.getCacheDir() File file=new File(MainApplication.getAppContext().getCacheDir(),System.currentTimeMillis()+".png"); try { BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file)); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos); bos.flush(); bos.close(); } catch (IOException e) { e.printStackTrace(); } return file.getPath(); } }
六、GridView的适配器 AppInfoAdapter.java
package net.zy13.skhelper.adapter; import android.annotation.SuppressLint; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import net.zy13.skhelper.R; import net.zy13.skhelper.entity.AppInfo; import java.util.List; public class AppInfoAdapter extends BaseAdapter { private Context context; private List<AppInfo> mAppinfoList; private OnItemClickListener mOnItemClickLitener; public AppInfoAdapter(Context context, List<AppInfo> mAppinfoList) { super(); this.context = context; this.mAppinfoList = mAppinfoList; } @Override public int getCount() { // TODO Auto-generated method stub return mAppinfoList.size(); } @Override public Object getItem(int arg0) { // TODO Auto-generated method stub return null; } @Override public long getItemId(int arg0) { // TODO Auto-generated method stub return 0; } @SuppressLint("NewApi") @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub AppInfo appInfo = mAppinfoList.get(position); // 加载布局 View view; ViewHolder viewHolder; if (convertView == null) { view = LayoutInflater.from(context).inflate(R.layout.appinfo_item, null); viewHolder = new ViewHolder(view); // 将ViewHolder存储在View中 view.setTag(viewHolder); } else { view = convertView; // 重新获取ViewHolder viewHolder = (ViewHolder) view.getTag(); } //设置控件的值 viewHolder.imageViewIcon.setImageDrawable(appInfo.getAppIcon()); String name=appInfo.getAppName(); viewHolder.textViewName.setText(name); return view; } class ViewHolder { ImageView imageViewIcon; TextView textViewName; public ViewHolder(View view) { this.imageViewIcon = (ImageView) view.findViewById(R.id.appinfo_item_icon); this.textViewName = (TextView) view.findViewById(R.id.appinfo_item_name); } } }
七、自定义分享窗口SharePopupWindow的调用
private LinearLayout mLayoutRoot; private ImageView mImageView; //获取根布局 mLayoutRoot=(LinearLayout)view.findViewById(R.id.LayoutRoot); //获取图片控件 mImageView=(ImageView)view.findViewById(R.id.image_qrcode); // 获取ImageView图片 mImageView.setDrawingCacheEnabled(true); Bitmap bitmap =Bitmap.createBitmap(mImageViewQrcode.getDrawingCache()); mImageView.setDrawingCacheEnabled(false); String imgpath=ShareUtil.SaveTitmapToCache(bitmap); //实例化分享窗口 SharePopupWindow spw = new SharePopupWindow(mContext); spw.setImgpath(imgpath); // 显示窗口 spw.showAtLocation(mLayoutRoot, Gravity.BOTTOM, 0, 0);
加载全部内容