Android原生态实现分享转发功能实例
程序员文章站
2022-06-23 11:16:03
目录导读: 一、xml布局文件二、创建一个实体类 appinfo.java,用来保存应用信息三、重写popupwindow控件sharepopupwindow.java,自定义分享的弹窗四、使用pro...
导读:
之前刚学安卓时,写过一篇“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);
到此这篇关于android原生态实现分享转发功能实例的文章就介绍到这了,更多相关android分享转发功能内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!