Ⅰ 【android】Permission denied (missing INTERNET permission)异常踩坑
自己在做项目的时候,发现APK在某厂家的一款机顶盒上开机启动的时候,接收开机广播拉起进程之后,进程突然崩溃,如果再次拉起进程,又能够正常前纳使用了,经过全局异常捕获发现,导致进程崩溃的原因居然是okhttp中抛出的一个异常:
第一眼看这个异常,肯定会想到,这特么的是没有加权限啊!!!然而事情如果有这么简单的话,还填个毛的坑啊!!!接下来,讲一下关于这个异常的情况。
对于这种异常,大部分情况下确实因为没有添加网络权限导致的,一般只需要添加
<uses-permission android:name="android.permission.INTERNET" />
该权限即可解决该异常引起的崩溃,然后我再项目中查了一遍又一遍,确认了一次又一次,确定不是由于未添加网络权限导致的该异常,难道还有其他原因?
查看了出现该异常的其他博客,也有人在孝腔出现该异常时添加如下权限就解决了的
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
事实上,依然没有效果,开机该崩溃还得崩溃;后来在想干脆将网络权限都加上,流氓点就流巧悔衫氓点,但该总不会导致这个异常了吧?
爽不过三秒,开启重启,还是崩溃了~~~~~~~
因为做大屏应用开发,很多应用需要在开机之后就要后台运行,如果开机进程挂了不能起来就玩完了。查了很多资料,目前尚不明确具体什么原因导致的该异常,初步定位为与ROM有关,但事情总得想法子解决的。如何解决?
既然是okHttp网络访问出现的异常导致的崩溃,那么我这边想法是通过okHttp拦截器来拦截该异常,并做相关处理。具体的拦截器写法如下:
所以我这里就是先搞一个定时器,10秒后定时发送广播,拉起自己,同时手动kill掉进程,这样既保证了崩溃平台不会大批量收集该异常,同时进程保证也能够正常再开机的时候运行,虽然kill了一次,但不影响业务,至此,虽然没找到具体的原因,但还是解决了该问题。
如果有哪位在使用oKhttop的时候也出现了这类异常,并且不是由于简单的权限问题导致的,分析到了原因还望告知,谢谢。
同步发布于掘金: https://juejin.im/post/5b129d295188257d86687532
Ⅱ android全局捕获异常使用详解
2.2: 在自己程序中BaseApplication中的onCreate()方法设置全局异常捕捉类
2.3:直接在MainActivity的initData()初始化数据方法中隐者,获取上次崩溃灶乎薯信息,然后打印即可
以上就是全局顷隐异常捕获及使用步骤,如若需要,直接拷贝到自己项目中即可使用
地址如下
https://www.jianshu.com/u/c5fabe27176e
Ⅲ Android 捕获全局异常CrashHandler,防止异常闪退,记录异常日志
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Looper;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* UncaughtException handler class
*
*/
public class CrashHandler implements UncaughtExceptionHandler {
public static final String TAG = "CrashHandler";
public static final String PROGRAM_BROKEN_ACTION = "com.teligen.wccp.PROGRAM_BROKEN";
private UncaughtExceptionHandler mDefaultHandler;
private static CrashHandler instance = new CrashHandler();
private Context mContext;
private Class<?> mainActivityClass;
private Map<String, String> infos = new HashMap<String, String>();
private CrashHandler() {
}
public static CrashHandler getInstance() {
return instance;
}
public void init(Context context, Class<?> activityClass) {
mContext = context;
this.setMainActivityClass(activityClass);
mDefaultHandler = Thread.();
Thread.(this);
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
mDefaultHandler.uncaughtException(thread, ex);
} else {
System.out.println("uncaughtException--->" + ex.getMessage());
// Log.e(TAG, ex.getMessage());
logError(ex);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// Log.e("debug", "error:", e);
}
exitApp();
}
}
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(mContext.getApplicationContext(),
"unknown exception and exiting...Please checking logs in sd card!", Toast.LENGTH_LONG).show();
Looper.loop();
}
}).start();
collectDeviceInfo(mContext.getApplicationContext());
logError(ex);
return true;
}
private void exitApp() {
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
public void collectDeviceInfo(Context ctx) {
try {
PackageManager pm = ctx.getPackageManager();
PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),
PackageManager.GET_ACTIVITIES);
if (pi != null) {
String versionName = pi.versionName == null ? "null"
: pi.versionName;
String versionCode = pi.versionCode + "";
infos.put("versionName", versionName);
infos.put("versionCode", versionCode);
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
Field[] fields = Build.class.getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
infos.put(field.getName(), field.get(null).toString());
} catch (Exception e) {
}
}
}
private void logError(Throwable ex) {
StringBuffer sb = new StringBuffer();
for (Map.Entry<String, String> entry : infos.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
sb.append(key + "=" + value + "\n");
}
int num = ex.getStackTrace().length;
for (int i=0;i<num;i++){
sb.append(ex.getStackTrace()[i].toString());
sb.append("\n");
}
File file = new File(filePath+"/log.txt");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write((sb.toString()+"exception:"+ex.getLocalizedMessage()).getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public Class<?> getMainActivityClass() {
return mainActivityClass;
}
public void setMainActivityClass(Class<?> mainActivityClass) {
this.mainActivityClass = mainActivityClass;
}
}
filePath是记录日志的路径
在Applicaton中初始化
@Override
public void onCreate() {
super.onCreate();
CrashHandler mCrashHandler = CrashHandler.getInstance();
mCrashHandler.init(getApplicationContext(), getClass());
initFile();
}
Ⅳ android 捕获系统异常并上传日志的实例
在做项目时,经常会把错误利用异常抛出去,这样在开发时就可以通过手机抛出的异常排查错误。但是当程序开发完毕,版本稳定,需要上线时,为了避免抛出异常影响用户感受,可以用UncaughtExceptionHandler捕获全局异常,对异常做出处理。比如我们可以获取到抛出异常的时间、手机的硬件信息、错误的堆栈信息,然后将获取到的所有的信息发送到服务器中行隐激,也可以发送到指定的邮件中,以档袜便及时修改bug。
示例:
自定义异常类实现UncaughtExceptionHandler接口,当某个页面出现异常就会调用uncaughtException这个方法携山,我们可以在这个方法中获取异常信息、时间等,然后将获取到的信息发送到我们指定的服务器
复制代码 代码如下:
/**
* 自定义的 异常处理类 , 实现了 UncaughtExceptionHandler接口
* @author Administrator
*
*/
public class MyCrashHandler implements UncaughtExceptionHandler {
// 需求是 整个应用程序 只有一个 MyCrash-Handler
private static MyCrashHandler myCrashHandler ;
private Context context;
private DoubanService service;
private SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
//1.私有化构造方法
private MyCrashHandler(){
}
public static synchronized MyCrashHandler getInstance(){
if(myCrashHandler!=null){
return myCrashHandler;
}else {
myCrashHandler = new MyCrashHandler();
return myCrashHandler;
}
}
public void init(Context context,DoubanService service){
this.context = context;
this.service = service;
}
public void uncaughtException(Thread arg0, Throwable arg1) {
System.out.println("程序挂掉了 ");
// 1.获取当前程序的版本号. 版本的.id
String versioninfo = getVersionInfo();
// 2.获取手机的硬件信息.
String mobileInfo = getMobileInfo();
// 3.把错误的堆栈信息 获取出来
String errorinfo = getErrorInfo(arg1);
// 4.把所有的信息 还有信息对应的时间 提交到服务器
try {
service.createNote(new PlainTextConstruct(dataFormat.format(new Date())),
new PlainTextConstruct(versioninfo+mobileInfo+errorinfo), "public", "yes");
} catch (Exception e) {
e.printStackTrace();
}
//干掉当前的程序
android.os.Process.killProcess(android.os.Process.myPid());
}
/**
* 获取错误的信息
* @param arg1
* @return
*/
private String getErrorInfo(Throwable arg1) {
Writer writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
arg1.printStackTrace(pw);
pw.close();
String error= writer.toString();
return error;
}
/**
* 获取手机的硬件信息
* @return
*/
private String getMobileInfo() {
StringBuffer sb = new StringBuffer();
//通过反射获取系统的硬件信息
try {
Field[] fields = Build.class.getDeclaredFields();
for(Field field: fields){
//暴力反射 ,获取私有的信息
field.setAccessible(true);
String name = field.getName();
String value = field.get(null).toString();
sb.append(name+"="+value);
sb.append("n");
}
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
/**
* 获取手机的版本信息
* @return
*/
private String getVersionInfo(){
try {
PackageManager pm = context.getPackageManager();
PackageInfo info =pm.getPackageInfo(context.getPackageName(), 0);
return info.versionName;
} catch (Exception e) {
e.printStackTrace();
return "版本号未知";
}
}
}
创建一个Application实例将MyCrashHandler注册到整个应用程序上,创建出服务并进行传递:
复制代码 代码如下:
/**
* 整个(app)程序初始化之前被调用
* @author Administrator
*
*/
public class DoubanApplication extends Application {
public NoteEntry entry;
@Override
public void onCreate() {
super.onCreate();
String apiKey = "";
String secret = "87fc1c5e99bfa5b3";
// 获取到service
DoubanService myService = new DoubanService("我的小豆豆", apiKey,
secret);
myService.setAccessToken("", "56a622c1138dbfce");
MyCrashHandler handler = MyCrashHandler.getInstance();
handler.init(getApplicationContext(),myService);
Thread.(handler);
}
}
Ⅳ androidstudio中怎么捕获异常
//可以使用try catch finally语句来捕获异常。
//代码格式:
try{
//如果要捕获异常,需要将代码放置在这try的代码块范围内
}catch(IOException ex){//异常范围IOException 以及它的派生类异常
//此处编写发生 IOException 或其派生类异常时处理方案
}catch(Exception ex){//异常范围Exception 以及它的派生类异常
//此处编写发生Exception 或其派生类异常时处理方案
}finally{
//此处无论上方的代码中是否出现了异常、return语句,这里必定执行。
}
/*
try catch语句至少需要有一个catch,却可以同时有多个catch。
其中catch语句块的异常范围从上到下顺序书写时应当从小范围到达范围,如果将Exception的catch与IOException的catch位置对换,那么永远不会执行IOException的catch块的代码
finally语句代码块是可选的。可以有它,也可以不使用它,具体是否启用它需要根据业务逻辑决定
*/
Ⅵ android 怎么捕获app异常闪退的日志
1、通过集成第三方SDK,如网络统计、友盟统计等
2、发版时使用加固工具,他们也会收集错误日志,如360加固
3、在程序中添加程序异常崩溃的捕捉代码,保存到本地文件中。
Ⅶ Android端的用户行为统计和日志打捞方案
提到移动客户端的优化,大家首先想到的可能就是页面的流畅度,也就是CPU和GPU的渲染问题,以此来提升用户的体验,然而对于CPU和GPU渲染的优化又是APP优化的两把尖刀,让一个app提升用户量和体验度有较高的推动力。然而让我们无法预估的就是用户的实际操作,也就是已经发出去的版本,我们很难知道用户喜欢什么功能和他们想要什么功能以及他们习惯于什么样的操作姿势,包括用户安装、卸载不用的情况,并且对潜在的线上崩溃问题,作为一位开发者我们就很想知道错误出现的精确位置以及错误信息,这些对一个APP的成长来说将是一个关键的导向作用,其实这也算是APP的一个比较重要的优化方案。
对于以上出现的问题,开发者更关心APP的Crash问题,而对于产品来说,他们更关心用户的喜好、行为和需求,以便于产品设计出更好的需求解决方案,目前市场上也出现了专门的问题解决方案,比如友盟统计、bugly统计、小米统计等,对于一个小型方案我们可以采用第三方的统计方案,但对于一个日活百万乃至千万的APP来说用第三方的统计方案就会受限很多,于是拥有自己的一套统计方案就显的刻不容缓了,掌握市场的方向,我们就掌握了主动权,那么我们怎样去设计一套准确优良的统计方案。
1.1 传统的pc端统计
以老牌的pc上的web页面统计一般有PV.UV,和IP之分,对于crash问题,本身web页面就存在远程的服务器端,日志将会保存在服务器的目录,所以一般web项目开发者无需考虑收集Log的case,那么我们更锋厅歼care的就是上面说的行为统计,下面说说这三种统计区别。
2. 2、IP、PV和UV分别是什么意思?
IP,实际上也就是指独立IP,是独立IP数的意思。00:00—24:00时间内相同IP地址只记录一次。即使你有多台电PC,但是如果IP地址是一样的,那么也只能算是一个IP的访问,IP数据依然为1。当然多台pc的ip一般都不一样,除非你插上同一个网络端口然伏睁后换零一台连接,都是一样,同时连接多台,每台pc的IP就是不一样的。
PV, 指访问量,它的英文是PageView,具体是指网站的是页面总浏览量或者点击量,页面被刷新一次就计算一次。如果网站被刷新了10次,那么流量统计工具显示的PV就是10 。
UV,它是独立访客的意思,英文为Unique Visitor。具体指访问您网站的一个客户端(移动设备或者是电PC)为一个访客。00:00-24:00内相同的客户端(mac地址区分)只被计算一次。
3 . 3 IP、PV和UV之间的关系是什么?
1.3.1.IP和PV之间的关系
PV是和IP的数量是成正比的,因为页面被刷新一次那么PV就会被记录一次,所以IP越多,说明网站的PV数据也就随之增多。但是需要注意的是PV并不是网站的页面的访问者数量,而是网站被访问的页面数量。因为一个访问者可以多次刷新页面,增加PV数量。
1.3.2 .IP和UV之间的关系:
在记录网站流量统计数据时,运维有时候发现这样一种情况:有时候网站的IP数据大于UV数据,有时候UV的数据也会大于IP数据。为什么会出现这种现象呢?我们可以用一个例子来说明。比如,用同一个IP去访问我们的某个网站,但是一个是用的台式的电脑,一个是用的笔记本,那么网站流量统计工具显示的数据就会是2个UV,1个IP。这时UV的数据就会大于IP的数据。但是,再比如,只是用一个台式电脑访问我们的网站,但是一会拨一个号换一个IP,那么这时候网站流量统计工具显示的数据的UV就为1,但是IP的数据就会高于UV的数据。因此,IP和UV之间的数据并不一定存在比例关系,两者之间银冲的数据也不是此消彼长的关系。
1.3.3.IP和PV之间的关系:
那么IP和PV的关系如何呢?如果一个IP刷新了网站100次,网站的PV就为100,所以从这点看二者之间没有多大关系。但是,我们可以通过IP和PV之间的数据差异,来更加深入的理解网站的流量数据。如果IP和PV的数据悬殊很大,比如,我们在查看网站流量数据时发现网站的PV是1000,IP为100,那么说明这个站点平均一个IP访问了网站内容10次,说明网站内容还是比较受欢迎的,所以访客才愿意在网站中停留那么久的时间,并浏览了那么多的网站页面内容。但是如果IP和PV的数据很接近,比如,网站的IP为100,PV为110,说明一个IP也就访问了网站内容大约1次,就说明网站内容的可读性太差,客户点击进去之后就离开了,没有有过多的停留。如果网站流量统计这样的数据过多的话,站长就需要对网站内容进行深入思考了,以便更好的提高网站的流量。
1.4 我们能从这边得到什么
鉴于已经很成熟的统计方案,我们在移动设备上(这里只说android)怎样实现一个完美的用户数据和行为统计,崩溃日志的套装方案呢。
那么我们的一个App,我们能做的那些方面呢
2.1 .1 用户数据(日活)
首先我们的可以加入ip,PV和UV统计模式,这样我们可以成功的get到app的日活,以及整体使用情况,
比如App启动了多少次,访问了多少h5页面,有多少个ip(设备)访问过,但是我们无法得native页面的信息(也就是Activity)服务端是是无法获取的,除非我们本地的页面有加载服务端数据的接口的功能,这种情况下服务是可以监控到本页面的数据流量的,但是在断网情况下,服务端是无法及时获取日活数据的,那么怎么解决呢,这里先不说,先看下个要解决的问题。
2.1.2 用户行为
获取到了APP整体流量后,怎么能知道某个功能受欢迎,或者某个本地页面经常被用户使用呢,则具体行为统计是app必须的, 目前一般由客户端和服务器端协商好一套自定义事件字典(也就是所谓的统计id对照表),当用户使用某个功能时,我们将对应的功能id发送到后台。这样服务端就有统计用户行为的能力了,那么这种只是一种初次尝试的想法,那么断网,或者功能多的情况子下,我们有如何采集用户行为呢
2.1.3 Log日志
那么对于线上的app版本,又是怎样收集carsh日志呢。一般我们在app崩溃的时候发送一条请求到服务端,是可以实现的,但没必要做,一般是将日志保存到本地,在某个时间或者case触发上报行为,
三 综合方式。
一般统计策略不会采用单一的方式进行上报,多采用组合的形式实现,服务器和客户端,有网和没网,实时和不定时。主动和被动的策略。
1 服务端
客户端请求接口是 统一包含特定的请求头,服务端的每个接口中可以去采集这些请求头 记录访问量 包括ip,PV,UV , 这样可以去捕获一定的用户数据。
服户端也可以采用推送的形式,让客户端去发送特定的采集好信息上报给服务器。
2 客户端
统计一般大多体现在客户端,我们可以将一个整体的app分解成多个模块,每个模块有多个功能,功能又分为用户主动和被动接受之分,给每个域分配一定的ID,那么在用户使用某个功能时 我们动态记录这个ID(比如登陆和注册一般属于用户中心(001),登陆和注册输入两种功能,分别给03,04标记,登陆属于用户主动 那么可以给 01,注册被动跳转给02), 最后写入到本地保存,那么用户打开用户中心登陆产生的的数据信息就0010201 ,这样服务器能知道,我们只要在某个时间点将文本数据上传即可,即使没网络情况下我们也不怕,等设备有网的情况下 我们偷偷上报即可,那么我们也可以在用户登陆的时候时侯同时就上传这些数据,这个策略视具体功而定。
一般一个APP统计有模块域 ,功能域,事件域,由大到小分配而来,也有按页面区分的,具体看实际的需求场景而定
对于我们的app crash 我们可以继承android自带的全局异常类(UncaughtExceptionHandler),来进行自我捕获异常,和用户行为一起上报。
也可以单独加个意见反馈功能,采集用户的吐槽和建议。
说了上面一大堆策略问题,对于开发而言很可能觉得很无聊,那么至于统计其实没什么技术含量(用户设备的唯一标识符除外),无非就是采集数据写到文件中,请求发送数据,最重要的还是一种策略的定义。
主流的多采用 时间戳,内存大小(日志积累到多大字节),次数(总计积累到多十条)等,
对于好的统计,我们可以检测网络,检测home建来触发我们的上报数据接口,也可以采用注册静态广播,用alarm 闹钟定时上报数据,然后这些技术也就是被大家玩透的功能而已,没必要再这里给大家补脑,但是注意的是
统计设备唯一标识符的确定, 这个以后再去分析.
统计上报接口采用分布式,不然所有数据都请求同一个接口,那么日活大的情况下,服务器挂了 不仅无法收到数据,反而影响客户端其他正常的功能
Ⅷ android 如何让应用程序只在有中断的时候才运行
在application中捕获全局异常,当有异常发生时,做你要做的事情。
Ⅸ android 程序怎样捕捉全局异常
Android系统的“程序异常退出”,给应用的用户体验造成不良影响。为了捕获应用运行时异常并给出友好提示,便可继承UncaughtExceptionHandler类来处理。通过Thread.()方法将异常处理类设置到线程族宽上即可。
1、异常处理类,喊山代码如兆渗亮下:
[java] view plain
public class CrashHandler implements UncaughtExceptionHandler {
public static final String TAG = "CrashHandler";
private static CrashHandler INSTANCE = new CrashHandler();
private Context mContext;
private Thread.UncaughtExceptionHandler mDefaultHandler;
private CrashHandler() {
}
public static CrashHandler getInstance() {
return INSTANCE;
}
public void init(Context ctx) {
mContext = ctx;
mDefaultHandler = Thread.();
Thread.(this);
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
// if (!handleException(ex) && mDefaultHandler != null) {
// mDefaultHandler.uncaughtException(thread, ex);
// } else {
// android.os.Process.killProcess(android.os.Process.myPid());
// System.exit(10);
// }
System.out.println("uncaughtException");
new Thread() {
@Override
public void run() {
Looper.prepare();
new AlertDialog.Builder(mContext).setTitle("提示").setCancelable(false)
.setMessage("程序崩溃了...").setNeutralButton("我知道了", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
System.exit(0);
}
})
.create().show();
Looper.loop();
}
}.start();
}
/**
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. 开发者可以根据自己的情况来自定义异常处理逻辑
*
* @param ex
* @return true:如果处理了该异常信息;否则返回false
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return true;
}
// new Handler(Looper.getMainLooper()).post(new Runnable() {
// @Override
// public void run() {
// new AlertDialog.Builder(mContext).setTitle("提示")
// .setMessage("程序崩溃了...").setNeutralButton("我知道了", null)
// .create().show();
// }
// });
return true;
}
}
2、线程绑定异常处理类
[java] view plain
public class CrashHandlerActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
CrashHandler crashHandler = CrashHandler.getInstance();
crashHandler.init(this); //传入参数必须为Activity,否则AlertDialog将不显示。
// 创建错误
throw new NullPointerException();
}
}