最近在做生成根据url生成二维码,并且将该页面的view生成图片的形式分享到各个应用平台的需求,在这里,我们用的第三方分享工具是ShareSDK,虽然说起来不是特别难,但是还是需要注意一下一些地方,在此记录下来开发的小细节,希望对需要帮助的小伙伴有益。
效果图如下:
那么需要做的工作有哪些呢?
- 生成二维码
在此提供生成二维码的jar包,网上看了一下,GitHub 上面的源码
(基于eclipse) 地址是:
https://github.com/zxing/zxing
打包成jar文件以供studio用户使用的地址是:
http://download.csdn.net/detail/lh11077/9466802
那么工具jar包有了,也就可以直接在项目中使用了
在这里定义一个工具类:
package com.ijuyin.prints.news.module.live.share;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.util.Hashtable;
/**
* -Created by suquanlin on 2017/5/18.
* 生成二维码的工具类
*/
class QRCode {
/**
* 生成二维码,默认大小为500*500
*
* @param text 需要生成二维码的文字、网址等
* @return bitmap
*/
public static Bitmap createQRCode(String text) {
return createQRCode(text, 500);
}
/**
* 生成二维码
*
* @param text 需要生成二维码的文字、网址等
* @param size 需要生成二维码的大小()
* @return bitmap
*/
public static Bitmap createQRCode(String text, int size) {
try {
Hashtable hints = new Hashtable<>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
BitMatrix bitMatrix = new QRCodeWriter().encode(text,
BarcodeFormat.QR_CODE, size, size, hints);
int[] pixels = new int[size * size];
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
if (bitMatrix.get(x, y)) {
pixels[y * size + x] = 0xff000000;
} else {
pixels[y * size + x] = 0xffffffff;
}
}
}
Bitmap bitmap = Bitmap.createBitmap(size, size,
Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, size, 0, 0, size, size);
return bitmap;
} catch (WriterException e) {
e.printStackTrace();
return null;
}
}
/**
* 生成带logo的二维码,默认二维码的大小为500,logo为二维码的1/5
*
* @param text 需要生成二维码的文字、网址等
* @param mBitmap logo文件
* @return bitmap
*/
public static Bitmap createQRCodeWithLogo(String text, Bitmap mBitmap) {
return createQRCodeWithLogo(text, 500, mBitmap);
}
/**
* 生成带logo的二维码,logo默认为二维码的1/5
*
* @param text 需要生成二维码的文字、网址等
* @param size 需要生成二维码的大小()
* @param mBitmap logo文件
* @return bitmap
*/
public static Bitmap createQRCodeWithLogo(String text, int size, Bitmap mBitmap) {
try {
int IMAGE_HALFWIDTH = size / 10;
Hashtable hints = new Hashtable<>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");//编码格式
hints.put(EncodeHintType.MARGIN, 0);//生成二维码的样式,也就是边距,(0,1,2,3),此处设置的是无边距样式,可自行定义
/*
* 设置容错级别,默认为ErrorCorrectionLevel.L
* 因为中间加入logo所以建议你把容错级别调至H,否则可能会出现识别不了
*/
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
BitMatrix bitMatrix = new QRCodeWriter().encode(text,
BarcodeFormat.QR_CODE, size, size, hints);
int width = bitMatrix.getWidth();//矩阵高度
int height = bitMatrix.getHeight();//矩阵宽度
int halfW = width / 2;
int halfH = height / 2;
Matrix m = new Matrix();
float sx = (float) 2 * IMAGE_HALFWIDTH / mBitmap.getWidth();
float sy = (float) 2 * IMAGE_HALFWIDTH
/ mBitmap.getHeight();
m.setScale(sx, sy);
//设置缩放信息
//将logo图片按martix设置的信息缩放
mBitmap = Bitmap.createBitmap(mBitmap, 0, 0,
mBitmap.getWidth(), mBitmap.getHeight(), m, false);
int[] pixels = new int[size * size];
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
if (x > halfW - IMAGE_HALFWIDTH && x < halfW + IMAGE_HALFWIDTH
&& y > halfH - IMAGE_HALFWIDTH
&& y < halfH + IMAGE_HALFWIDTH) {
//该位置用于存放图片信息
//记录图片每个像素信息
pixels[y * width + x] = mBitmap.getPixel(x - halfW
+ IMAGE_HALFWIDTH, y - halfH + IMAGE_HALFWIDTH);
} else {
if (bitMatrix.get(x, y)) {
pixels[y * size + x] = 0xff000000;
} else {
pixels[y * size + x] = 0xffffffff;
}
}
}
}
Bitmap bitmap = Bitmap.createBitmap(size, size,
Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, size, 0, 0, size, size);
return bitmap;
} catch (WriterException e) {
e.printStackTrace();
return null;
}
}
}
这里是详细的生成二维码矩阵的code,当然了,这里是适用于二维码中间带有图片的类型,该类的用法也很easy。
Bitmap bitmap = QRCode.createQRCodeWithLogo(myLiveIntroductionModel.getUrl(), 300,
BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher));
ivQrCode.setImageBitmap(bitmap);
注意:
- ivQrCode:定义的是一个装二维码的ImageView;
- myLiveIntroductionModel.getUrl(): 需要生成二维码的网址;
- R.mipmap.ic_launcher:这个是二维码中间放置的小图片;
- 300:创建一个大小为300的二维码;
很简单的就根据你所需要的url生成了相应的二维码。
2.将View的内容映射成Bitmap转图片导出
/**
* 将View的内容映射成Bitmap转图片导出
*
* @param view RelativeLayout
* @return Bitmap
*/
public static Bitmap getViewToImage(View view) {
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.destroyDrawingCache();
view.setDrawingCacheEnabled(false);
return bitmap;
}
用法:Bitmap myBitmap = getViewToImage(layShare);
(此处的view则是需要生成的布局的view,此处是RelativeLayout)
3.拿到文件的路径,这里的myBitmap就是上文中拿到的生成的Bitmap
/**
* 拿到文件路径
*
* @return String
*/
private String getFilePath() {
String mImageUrl = convertIconToString(myBitmap);
StringBuilder sb = new StringBuilder();
if (!TextUtils.isEmpty(mImageUrl) && mImageUrl.contains("/")) {
try {
sb.append(mImageUrl.substring(mImageUrl.lastIndexOf("/") + 1,
mImageUrl.length()));
} catch (Exception e) {
e.printStackTrace();
sb.append(String.valueOf(System.currentTimeMillis()));
}
} else {
sb.append(String.valueOf(System.currentTimeMillis()));
}
sb.append(".png");
return PrintsFileUtil.getSaveImageFileDir().getAbsolutePath() +
File.separator + sb.toString();
}
保存bitmap
/**
* 保存bitmap
*/
public void saveBitmap() {
//拿到上面的文件路径
String path = getFilePath();
if (path != null) {
boolean result = PrintsImageUtil.saveFile(path, myBitmap);
//text_image_save:保存成功
//text_image_save_failed:保存失败
ToastUtil.getInstance().show(result ? R.string.text_image_save : R.string
.text_image_save_failed);
}
}
bitmap转String(拿到文件路径中调用bitmap转为string)
/**
* bitmap转String
*
* @param bitmap bitmap
* @return String
*/
public static String convertIconToString(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] appicon = baos.toByteArray();// 转为byte数组
return Base64.encodeToString(appicon, Base64.DEFAULT);
}
4.ShareSdk各个渠道的分享这里我做的分享的设计涉及到四个渠道(新浪微博,微信,微信朋友圈, qq )
这里需要注意下:
- 因为qq空间对于单纯图片的分享有所限制,QQ空间分享时一定要携带title、titleUrl、site、siteUrl,QQ空间本身不支持分享本地图片;
- 因此如果想分享本地图片,图片会先上传到ShareSDK的文件服务器,得到连接以后才分享此链接。
- 由于本地图片更耗流量,因此imageUrl优先级高于imagePath。 site是分享此内容的网站名称,仅在QQ空间使用;
- siteUrl是分享此内容的网站地址,仅在QQ空间使用,用ShareSdk做QQ空间分享的小伙伴请看这里哟。
新浪微博分享:
//首先判断有没有安装新浪微博
public static boolean isWeiboInstalled(@NonNull Context context) {
PackageManager pm;
if ((pm = context.getApplicationContext().getPackageManager()) == null) {
return false;
}
List packages = pm.getInstalledPackages(0);
for (PackageInfo info : packages) {
String name = info.packageName.toLowerCase(Locale.ENGLISH);
if ("com.sina.weibo".equals(name)) {
return true;
}
}
return false;
}
/**
* 新浪微博分享,PlatformActionListener是对分享回调的状态回调
* @param where 新浪微博:SinaWeibo,微信:Wechat,微信朋友圈:WechatMoments,QQ:QQ
*/
private void getSharePlatFrom(String where) {
myBitmap = getViewToImage(layShare);
Platform.ShareParams mySp = new Platform.ShareParams();
mySp.setShareType(Platform.SHARE_IMAGE);
if (myBitmap != null) {
String mImageUrl = getFilePath();
if (!TextUtils.isEmpty(mImageUrl) && !isSaved) {
isSaved = PrintsImageUtil.saveFile(mImageUrl, myBitmap);
}
mySp.setImagePath(mImageUrl);
}
Platform plat = ShareSDK.getPlatform(where);
platformActionListener = new PlatformActionListener() {
@Override
public void onComplete(Platform platform, int i, HashMap hashMap) {
closeDialog();
}
@Override
public void onError(Platform platform, int i, Throwable throwable) {
closeDialog();
Message msg = handler.obtainMessage();
msg.what = SHARE_FAIL;
msg.arg1 = i;
msg.obj = throwable;
ShareActivity.this.handler.sendMessage(msg);
}
@Override
public void onCancel(Platform platform, int i) {
closeDialog();
}
};
plat.setPlatformActionListener(platformActionListener);
plat.share(mySp);
}
//回调回来异步执行相应错误的反馈
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SHARE_FAIL:
String failText = "";
if (msg.obj instanceof WechatClientNotExistException) {
failText = getResources().getString(R.string.wechat_client_inavailable);
} else if (msg.obj instanceof WechatTimelineNotSupportedException) {
failText = getResources().getString(R.string.wechat_client_inavailable);
} else if (msg.obj instanceof java.lang.Throwable &&
msg.obj.toString() != null && msg.obj.toString().
contains("prevent duplicate publication")) {
failText = getResources().getString(R.string.prevent_duplicate);
} else if (msg.obj.toString().contains("error")) {
failText = getResources().getString(R.string.share_failed_error);
} else {
failText = getResources().getString(R.string.share_failed_error);
}
LogUtil.e("WechatClientNotExistException msg.obj", msg.obj + "");
EdjTools.showShortToast(failText, ShareActivity.this);
break;
}
}
};
完整的类的代码:
package com.ijuyin.prints.news.module.live.share;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.ijuyin.prints.news.R;
import com.ijuyin.prints.news.base.BaseApplication;
import com.ijuyin.prints.news.module.BaseActivity;
import com.ijuyin.prints.news.module.live.Introduction.LiveIntroductionModel;
import com.ijuyin.prints.news.utils.LogUtil;
import com.ijuyin.prints.news.utils.LoginUtil;
import com.ijuyin.prints.news.utils.PrintsFileUtil;
import com.ijuyin.prints.news.utils.PrintsImageUtil;
import com.ijuyin.prints.news.utils.TextViewUtil;
import com.ijuyin.prints.news.utils.ToastUtil;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import cn.sharesdk.framework.Platform;
import cn.sharesdk.framework.PlatformActionListener;
import cn.sharesdk.framework.ShareSDK;
import cn.sharesdk.tencent.qq.QQ;
import cn.sharesdk.wechat.utils.WechatClientNotExistException;
import cn.sharesdk.wechat.utils.WechatTimelineNotSupportedException;
/**
* -Created by suquanlin on 2017/5/18.
* 分享页面
*/
public class ShareActivity extends BaseActivity {
@BindView(R.id.lay_share)
RelativeLayout layShare;
@BindView(R.id.tv_title)
TextView tvTitle;
@BindView(R.id.tv_title_sed)
TextView tvTitleSed;
@BindView(R.id.tv_time)
TextView tvTime;
@BindView(R.id.iv_qr_code)
ImageView ivQrCode;
@BindView(R.id.lay_share_weibo)
LinearLayout layShareWeibo;
@BindView(R.id.lay_share_wechat)
LinearLayout layShareWechat;
@BindView(R.id.lay_share_timeline)
LinearLayout layShareTimeline;
@BindView(R.id.lay_share_qq)
LinearLayout layShareQq;
private final static int SHARE_FAIL = 100;
private PlatformActionListener platformActionListener;
private LiveIntroductionModel myLiveIntroductionModel;
private Bitmap myBitmap;
private boolean isSaved;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SHARE_FAIL:
String failText = "";
if (msg.obj instanceof WechatClientNotExistException) {
failText = getResources().getString(R.string.wechat_client_inavailable);
} else if (msg.obj instanceof WechatTimelineNotSupportedException) {
failText = getResources().getString(R.string.wechat_client_inavailable);
} else if (msg.obj instanceof java.lang.Throwable &&
msg.obj.toString() != null && msg.obj.toString().
contains("prevent duplicate publication")) {
failText = getResources().getString(R.string.prevent_duplicate);
} else if (msg.obj.toString().contains("error")) {
failText = getResources().getString(R.string.share_failed_error);
} else {
failText = getResources().getString(R.string.share_failed_error);
}
LogUtil.e("WechatClientNotExistException msg.obj", msg.obj + "");
EdjTools.showShortToast(failText, ShareActivity.this);
break;
}
}
};
public PlatformActionListener getPlatformActionListener() {
return platformActionListener;
}
public void setPlatformActionListener(PlatformActionListener platformActionListener) {
this.platformActionListener = platformActionListener;
}
@Override
protected int getContentViewId() {
return R.layout.activity_share;
}
@Override
protected void initData(Bundle savedInstanceState) {
Intent i = getIntent();
if (i != null) {
myLiveIntroductionModel = (LiveIntroductionModel) i.getSerializableExtra
("liveIntroductionModel");
}
}
@Override
protected void initViews() {
ButterKnife.bind(this);
setCommonBack();
setMainTitle(R.string.txt_share_ye_title);
if (myLiveIntroductionModel != null) {
tvTitle.setText(myLiveIntroductionModel.getTitle());
tvTitleSed.setText(myLiveIntroductionModel.getPgc_name());
tvTime.setText(myLiveIntroductionModel.getStart_time());
Bitmap bitmap = QRCode.createQRCodeWithLogo(myLiveIntroductionModel.getUrl(), 300,
BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
ivQrCode.setImageBitmap(bitmap);
}
setNextText(R.string.text_btn_save, v -> {
myBitmap = getViewToImage(layShare);
if (myBitmap != null) {
saveBitmap();
}
});
}
private static class EdjTools {
private static void showShortToast(String message, Context context) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
}
@OnClick({R.id.lay_share_weibo, R.id.lay_share_wechat, R.id.lay_share_timeline, R.id
.lay_share_qq})
public void onClick(View view) {
switch (view.getId()) {
case R.id.lay_share_weibo:
shareSinaWeibo();
break;
case R.id.lay_share_wechat:
if (!BaseApplication.api.isWXAppInstalled()) {
ToastUtil.getInstance().show(R.string.text_share_not_found_wechat);
return;
}
showWaitingDialog(true);
getSharePlatFrom("Wechat");
break;
case R.id.lay_share_timeline:
if (!BaseApplication.api.isWXAppInstalled()) {
ToastUtil.getInstance().show(R.string.text_share_not_found_wechat);
return;
}
showWaitingDialog(true);
getSharePlatFrom("WechatMoments");
break;
case R.id.lay_share_qq:
showWaitingDialog(true);
getSharePlatFrom(QQ.NAME);
break;
}
}
/**
* 新浪微博分享,PlatformActionListener是对分享回调的状态回调
* @param where 新浪微博:SinaWeibo,微信:Wechat,微信朋友圈:WechatMoments,QQ:QQ
*/
private void getSharePlatFrom(String where) {
myBitmap = getViewToImage(layShare);
Platform.ShareParams mySp = new Platform.ShareParams();
mySp.setShareType(Platform.SHARE_IMAGE);
if (myBitmap != null) {
String mImageUrl = getFilePath();
if (!TextUtils.isEmpty(mImageUrl) && !isSaved) {
isSaved = PrintsImageUtil.saveFile(mImageUrl, myBitmap);
}
mySp.setImagePath(mImageUrl);
}
Platform plat = ShareSDK.getPlatform(where);
platformActionListener = new PlatformActionListener() {
@Override
public void onComplete(Platform platform, int i, HashMap hashMap) {
closeDialog();
}
@Override
public void onError(Platform platform, int i, Throwable throwable) {
closeDialog();
Message msg = handler.obtainMessage();
msg.what = SHARE_FAIL;
msg.arg1 = i;
msg.obj = throwable;
ShareActivity.this.handler.sendMessage(msg);
}
@Override
public void onCancel(Platform platform, int i) {
closeDialog();
}
};
plat.setPlatformActionListener(platformActionListener);
plat.share(mySp);
}
@Override
protected void onResume() {
super.onResume();
closeDialog();
}
//新浪微博分享
private void shareSinaWeibo() {
if (!isWeiboInstalled(BaseApplication.getInstance().getBaseContext())) {
ToastUtil.getInstance().show(R.string.text_share_not_found_weibo);
return;
}
showWaitingDialog(true);
Platform.ShareParams sp = new Platform.ShareParams();
sp.setShareType(Platform.SHARE_IMAGE);
myBitmap = getViewToImage(layShare);
if (myBitmap != null) {
String path = getFilePath();
if (myBitmap != null) {
if (!TextUtils.isEmpty(path) && !isSaved) {
isSaved = PrintsImageUtil.saveFile(path, myBitmap);
}
}
sp.setImagePath(path);
}
Platform weibo = ShareSDK.getPlatform("SinaWeibo");
platformActionListener = new PlatformActionListener() {
@Override
public void onComplete(Platform platform, int i, HashMap hashMap) {
closeDialog();
}
@Override
public void onError(Platform platform, int i, Throwable throwable) {
closeDialog();
Message msg = handler.obtainMessage();
msg.what = SHARE_FAIL;
msg.arg1 = i;
msg.obj = throwable;
ShareActivity.this.handler.sendMessage(msg);
}
@Override
public void onCancel(Platform platform, int i) {
closeDialog();
}
};
weibo.share(sp);
}
//首先判断有没有安装新浪微博
public static boolean isWeiboInstalled(@NonNull Context context) {
PackageManager pm;
if ((pm = context.getApplicationContext().getPackageManager()) == null) {
return false;
}
List packages = pm.getInstalledPackages(0);
for (PackageInfo info : packages) {
String name = info.packageName.toLowerCase(Locale.ENGLISH);
if ("com.sina.weibo".equals(name)) {
return true;
}
}
return false;
}
/**
* 拿到文件路径
*
* @return String
*/
private String getFilePath() {
String mImageUrl = convertIconToString(myBitmap);
StringBuilder sb = new StringBuilder();
if (!TextUtils.isEmpty(mImageUrl) && mImageUrl.contains("/")) {
try {
sb.append(mImageUrl.substring(mImageUrl.lastIndexOf("/") + 1,
mImageUrl.length()));
} catch (Exception e) {
e.printStackTrace();
sb.append(String.valueOf(System.currentTimeMillis()));
}
} else {
sb.append(String.valueOf(System.currentTimeMillis()));
}
sb.append(".png");
return PrintsFileUtil.getSaveImageFileDir().getAbsolutePath() +
File.separator + sb.toString();
}
/**
* 保存bitmap
*/
public void saveBitmap() {
String path = getFilePath();
if (path != null) {
boolean result = PrintsImageUtil.saveFile(path, myBitmap);
ToastUtil.getInstance().show(result ? R.string.text_image_save : R.string
.text_image_save_failed);
}
}
/**
* bitmap转String
*
* @param bitmap bitmap
* @return String
*/
public static String convertIconToString(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] appicon = baos.toByteArray();// 转为byte数组
return Base64.encodeToString(appicon, Base64.DEFAULT);
}
/**
* 将View的内容映射成Bitmap转图片导出
*
* @param view RelativeLayout
* @return Bitmap
*/
public static Bitmap getViewToImage(View view) {
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.destroyDrawingCache();
view.setDrawingCacheEnabled(false);
return bitmap;
}
@Override
protected void onDestroy() {
super.onDestroy();
//及时回收Bitmap对象,防止OOM
if (myBitmap != null && !myBitmap.isRecycled()) {
myBitmap.recycle();
}
}
}
完整分享的图片是这样的:
针对于qq平台的分享页面是这样的:
以上就是所有,生成二维码,图片式分享,保存图片到本地的所有代码,希望对小伙伴有益。