几个不错的Android开源音视频播放器

整理了一下Github上几个开源的音视频播放器项目,有兴趣的同学可以clone代码去研究学习。

UniversalMusicPlayer

https://github.com/googlesamples/android-UniversalMusicPlayer

这是Google开源的一个音频播放器项目,它向我们展示了如何在不同的设备上(Android phones, tablets, Android Auto, Android Wear, Android TV and Google Cast)提供一致的用户体验。

StylishMusicPlayer

https://github.com/ryanhoo/StylishMusicPlayer

采用RxJava开发的本地音乐播放器,UI图标都是Material Design上找的,最终作品颜值如下。

继续阅读全文 »

搭建个人博客,你需要知道这些

一个多月前开始筹备搭建自己的个人博客,由于要等国内备案完成,因此直到这两天才算完全搞定。今天把个人博客搭建需要了解的相关知识整理一下,希望可以给同样想建站的同学提供一点参考。

博客生成器

一个网站最基础的部分就是网页,如果想从HTML页面写起,显然成本太高,好在大牛们已经做好了博客生成器来解决网页编写的问题。一般来说,博客生成器分为动态和静态两种。其中,动态博客生成器典型代表有:WordPress、FarBox、Ghost等,静态的博客生成器典型代表有:Hexo、Jekyll、Octopress、Hugo等。关于动态和静态的区别主要有以下几点:

  • 资源占用上,静态的相比动态占用服务器资源少,还可以托管在Github Pages上;
  • 发布更新操作上,由于静态博客没有管理后台,所以发布更新内容要比动态博客繁琐;
  • 访问速度上,由于静态博客没有数据库,所以访问速度更快;
  • 安全性上,静态博客相比动态博客免疫了很多Web攻击套路;

我的博客便是选择了Hexo这个静态博客生成器。

Web服务器

有了博客生成器后,只需按照对应官方文档配置即可生成一个最简单的本地博客站点,如果想要让网络上人能够访问,你还需要将将其部署上服务器才行。对于服务器的选择,肯定要选择知名的服务器提供商,相对来说会比较稳定靠谱,国内的UCloud、阿里云、腾讯云、七牛云,国外的有亚马逊。如果使用静态博客生成器,还可以考虑用Github Pages,这样可以节省一笔租服务器的开销,对于还没有收入的在校学生,是个很不错的选择。不过,Github偶尔在国内无法访问,这点得做好心理准备。

继续阅读全文 »

Android开发时,那些相见恨晚的工具或网站!

本文来我在知乎话题Android开发时你遇到过什么相见恨晚的工具或网站?下的回答!

Android开发时你遇到过什么相见恨晚的工具或网站?

在实际Android开发过程确实会有很多相见恨晚的工具或网站出现,下面是我自己的一些分享。

源码网站

https://github.com/googlesamples

Android系统每次推出一些新特性,Google都会写一些Demo放在Github上,对于想要了解新特性怎么玩的同学,肯定不能错过它。

https://www.codota.com/

如果你不知道一个Android的类怎么用,可以在Codota上面快速的找到很多不错的示例代码。

https://android-arsenal.com/

你是否还在为找不到合适的开源库而苦恼,Android Arsenal这个网站已经帮你做了一定的分类,可以帮你提高不少效率。

https://android.googlesource.com/

Android所有的源代码都在这里,只需找到对应想要的模块,用Git克隆下来即可。比如,我想要的framework代码

http://androidxref.com/

克隆Android一个模块的代码量是很多的,有时候我只想要几个类的代码怎么办?AndroidXRef这个网站可以让你单独搜索某个类,要哪几个下载哪几个即可。

http://grepcode.com/

除了AndroidXRef可以查看某个类的源代码外,GrepCode同样也能做到。而且GrepCode不限于Android的源码,这里也推荐一下。

源码分析

源码分析的网站很多,这里举几个比较经典的网站。

继续阅读全文 »

Android应用安全风险与防范

近段时间在做Android应用安全方面的功课,本文进行简单梳理方便以后Review,有错误和遗漏之处还请大家指出。

代码混淆

Android开发除了部分功能采用C/C++编码外,其余主要都是采用Java进行编码开发功能。Java应用非常容易被反编译,Android自然也不例外。只要利用apktool等类似的反编译工具,就可以通过安装包获取源代码。Google为了保护开发者的知识产权,为Android提供了ProGuard混淆方案,以增加反编译后源码阅读,但对于Android开发老司机和逆向工程师来说,解读还原出源代码只是时间问题。

ProGuard是针对Java应用的保护,并不是专门针对Android应用的,Android虽然使用Java开发,但是毕竟不是跑在JVM上,所以安装包结构和普通的Java应用还是区别多多。如果你对免费的ProGuard放心不下,可考虑试试付费的混淆方案DexGuard,除了拥有ProGuard的功能外,还包含资源混淆,字符串加密,类加密和dex文件分割等。

虽然代码混淆是最为基础的保护措施,不过国内仍有不少应用还是裸奔的,其中还包括一些大厂应用(此处不表)。

签名校验

Android黑产里面,有一个叫做二次打包,也称为重打包。即通过反编译正版应用后,可以获得smali源码,往其中注入代码或者修改相应业务逻辑后,再利用新的签名进行重新打包,并发布到应用市场去,很多无良开发者就是通过这种方式去破解一些付费应用或者往其中注入广告代码来获利。简单梳理一下重打包的基本流程:

  1. 对正版应用用apktool类逆向工具进行解包;
  2. 在某处地方注入smali代码;
  3. 利用IDE生成签名文件,再通过jarsigner进行签名;
  4. 上传应用市场;

为了与二次打包做对抗,可以在应用内的关键功能入口增加校验签名的检测,如果发现应用签名非正版,则强制关闭应用或者限制用户使用。加签名校验代码时,可以考虑:

继续阅读全文 »

Android应用瘦身,从18MB到12.5MB

最近在为我们开发的直播应用做 Android 端的安装包瘦身,花了大概一周的时间把安装包从 18MB 减小到了 12.5MB。原本完全可以优化到 10MB 之下,但由于其他原因的限制,所以目前阶段只到 12.5MB 为止。在此记录一下优化的思路和用到的工具,方便自己以后 Review ,有需要的童鞋也可供参考。

瘦身的目的

从目的导向来看,我们是不会无缘无故去做一件事情的,那我们对应用瘦身的目的是为了什么?答案是:提高下载转化率。什么是下载转化率?举个栗子:你的应用大小是 18MB ,有100个潜在用户想要去下载尝试使用,结果有20个用户嫌弃安装包太大直接扬长而去,有20个用户在等待下载的过程中取消下载,最终只有60个用户真正下载安装,那么应用的下载转化率就是 60/100 = 60% 。

简单的小结便是:安装包越小,用户下载等待的时间越短,对手机存储配置小的设备体验愈佳,应用的下载转化率也就越高。记得以前在腾讯大讲堂听微信大牛说过,微信第一个版本只有差不多 400KB ,瞬间膜拜。

安装包的组成

要对安装包做瘦身,首先需要了解安装包的组成结构,这里简单的梳理了一下组成各个部分及其作用:

其中,在安装包中占比较大的包括:dex文件、res文件夹、assets文件夹、lib文件夹以及resource.arsc文件。所以,接下来的瘦身优化就是让这些文件变小,以此达到瘦身的目的。

在 Android Studio 2.2.3 开始,就加入了浏览 APK 结构的功能,我们直接把安装包拖入 IDE ,就可以直接浏览其组成和对应大小,这样能够很方便的对比分析出每一步优化后的结果。

继续阅读全文 »

走过2016时,我成长些什么

时间过得超快,2016年转眼间就剩下那么几天,每到年尾都要对整整的一年做个总结,本文便是我的2016总结稿。

开发成长篇

一直以来,我主要都是从事 Android 开发这块的工作,对于后端或者 Web 端这块的,很多知识还停留在校园教科书式的时代。原本今年年初计划要重拾 Java 后端、 Web 端和 Python 这块,重新拓展一下自己的技术栈,但是上半年由于个人原因,导致原本想要开始的计划延迟了半年,下半年才开始执行计划,目前有闲暇时间都在看关于 Web 端和 Java 后端的,Python 这块至今还未动,这算是2016最大的遗憾了。

对于我来说,由于一直以来都是做客户端开发工作,很多问题的思考有一定程度局限在客户端视觉。有时候处在客户端的角度看待问题,得出来一些解决方案具有很多局限性。为了弥补自己思考方式上的短板,我在尝试从自己原本的圈子里走出来,站在不同的角度去看待业务需求的实现,这样得到的方案会更加具有可实践性。后端语言众多,为何选择 Java ?主要是当前 Java 是主流,外加 Android 开发也用的是 Java ,可以省去学新语法的时间。就学习来说,语言不是重点,相信如果打通了 Java 后端的任督二脉,换一种后端语言也可以很快入门上手。

随着 H5 、 HyBird 、 RN 、 Weex 、 微信小程序以及 Google 在 GDD 上提出的 Progressive Web AMPs 的出现,很多原本要原生 App 实现的功能,都交给了 Web 端的童鞋,甚至有些小公司,客户端的童鞋同时还要搞 Web 端的事。说实话,我对 Web 端的开发很久前就非常感兴趣,这些新技术的出现更加触发了我跃跃欲试的冲动。从实际应用场景来说,这种移动端的 Web 开发确实有很多很好的应用场景,但并不是所有的场景都适合使用。所以,我从来都不信 Web 即将取代原生应用的鬼话。站在开发者的角度来说,关注技术发展的趋势并学习一些新技术是非常必要的,而那些死守着自己一亩三分地的开发者是注定要被时代淘汰的。

继续阅读全文 »

Android应用内存泄漏的定位、分析与解决策略

最近一直在为项目做内存泄漏的优化工作,本文用于记录一些排查优化的思路和方案,以及介绍一些辅助工具。

什么是内存泄漏

对于不同的语言平台来说,进行标记回收内存的算法是不一样的,像 Android(Java)则采用 GC-Root 的标记回收算法。下面这张图就展示了 Android 内存的回收管理策略(图来自Google 2011的IO大会)

图中的每个圆节点代表对象的内存资源,箭头代表可达路径。当圆节点与 GC Roots 存在可达路径时,表示当前资源正被引用,虚拟机是无法对其进行回收的(如图中的黄色节点)。反过来,如果圆节点与 GC Roots 不存在可达路径,则意味着这块对象的内存资源不再被程序引用,系统虚拟机可以在 GC 过程中将其回收掉。

有了上面的内存回收的栗子,那么接下来就可以说说什么是内存泄漏了。从定义上讲,Android(Java)平台的内存泄漏是指没有用的对象资源任与GC-Root保持可达路径,导致系统无法进行回收。举一个最简单的栗子,我们在 Activity 的 onCreate 函数中注册一个广播接收者,但是在 onDestory 函数中并没有执行反注册,当 Activity 被 finish 掉时,Activity 对象已经走完了自身的生命周期,应该被资源回收释放掉,但由于没有反注册, 此时 Activity 和 GC-Root 间任然有可达路径存在,导致 Activity 虽然被销毁,但是所占用的内存资源却无法被回收掉。类似的栗子其实有很多,不一一例举了。对于 Android(Java)内存回收管理想要再深入了解的童鞋,可以看看下面资源:

泄漏的源头

了解完内存泄漏的理论知识后,再来归类一下内存泄漏的源头。这里我将其归位以下三类:

继续阅读全文 »

深入了解 Messenger 的实现细节

本文是阅读 Messenger 源码的一点记录,看这篇文章前,需要对 Android 的进程间通讯方式有所了解,不然可能会云里雾里。

从使用 Messenger 说起

Android 上实现 IPC (进程间通讯)的方式有好几种,其中有一种就是使用 AIDL 方式实现,对使用 AIDL 不了解的童鞋可以看下方的官方文档(需要梯子)。

https://developer.android.com/guide/components/aidl.html

对于使用 AIDL 方式通讯,其关键就在于创建 aidl 文件,系统会自动为 aidl 文件生成相应的 Java 类,其关键实现在于生成的 Java 类中。

系统提供了一个更方便我们进行 IPC 的类 —— Messenger,先来看看如何使用 Messenger(熟悉的童鞋完全可以跳过这一部分)。

  • 第一步:客户端进程创建两个 Messenger,一个 Sender ,一个 Receiver;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//客户端进程发消息给服务进程
private Messenger mSender;
//客户端进程接收服务进程回调
private Messenger mReceiver = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle data = msg.getData();
if (data != null) {
String response = data.getString("body");
Toast.makeText(MainActivity.this, response, Toast.LENGTH_SHORT).show();
}
}
});
  • 第二步:编写Service类,并需要在 AndroidManifest.xml 配置多进程;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class IPCService extends Service {
private Messenger messenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
try {
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message response = Message.obtain();
Bundle data = new Bundle();
data.putString("body", "response");
response.setData(data);
try {
msg.replyTo.send(response);//回调客户端
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();//将Binder返回给请求绑定的进程
}
}
  • 第三步:绑定Service进程,并在 ServiceConnection 中初始化 Sender;

继续阅读全文 »

ScratchView:一步步打造万能的 Android 刮奖效果控件

我身边有一部分开发的小伙伴,存在着这样一种习惯。某一天,突然看到某一款 App 上有个很漂亮的自定义控件(动画)效果,就会绞尽脑子想办法去自己实现一发。当然,我自己也是属于这类型的骚年,看到某种效果就会手痒难耐琢磨着实现套路。个人觉得这是一种需求驱动进步的方法,当你绞尽脑子去实现自己想要的效果时,你就会发现你对 Android 自定义控件(动画)的知识体系认识越深,久而久之,自己也能轻松的造出各种控件(动画)效果。要是哪天,产品童鞋拿着个原型(或者对着某款 App )跟你讲:“XXXX,你看这个效果我们能不能实现?”,然后你瞥了一眼,胸有成竹丢回一句:“开玩笑,还有我实现不了的效果?”。想想心里是不是有点小激动?好了,差不多要说回正题了,这是我第一篇关于自定义控件的文章,以也会陆续穿插更新此类型的文章,希望大家能够喜欢。(偷偷剧透下,我下篇文章是关于性能优化的干货。当然我自己觉得很干货,希望到时候发出来不要打脸,哈哈哈!)

实现效果

说了这么多,还是先给大家看看最终的实现效果先

上面只是基本实现效果的一部分,你会看到下方还有很多其他控件,它们是用来干嘛的,接下来即将为你揭晓一切。

基本实现

日常生活中,我们对刮奖效果想必不会陌生,其原理就是通过在原有图案和文字上添加刮层来实现的。如果我们想看到刮层后面藏的图案和文字是什么,势必要通过刮开刮层才行。知道了这样的套路,就可以开始整理一下编码实现思路,然后愉快开干。

我一开始的实现思路是想通过重写 ImageView 和 TextView ,然后在分别用代码在图像和文字上添加图层,这样的话就能实现出效果了。然而回头一想,不对,这种实现存在的局限性比较大。如果照这种思路实现,那么刮层下面只能存在图片或者文字,如果产品经理要求同时存在图片和文字呢?要求存在两张图片呢?要求同时存在图片和文字,且文字放在图片的上(下、左、右)呢?…我们都知道,世界上最善变的除了妹纸的心,就是产品经理和他们的需求了。于是,便想出另外一种实现思路,直接继承 View 来实现一个刮层,让这个刮层和图片以及文字不产生任何依赖,再结合 FrameLayout 将刮层放置最上一层,刮层之下你想放多少图片文字,图片文字要怎么布局摆放都行。到此,思路明确,可以愉快的开始编码了。

继续阅读全文 »

知乎和简书的Android客户端夜间模式实现方式

说到夜间模式,在网上看到很多童鞋都说用什么什么框架来实现这个功能,然后仔细去看一下各个推荐的框架,发现其实都是动态换肤的,动态换肤可比夜间模式要复杂多了,未免大材小用了。说实话,我一直没用什么好思路,虽然网上有童鞋提供了一种思路是通过 setTheme 然后再 recreate Activity 的方式,但是这样带来的问题是非常多的,看起来就相当不科学(为什么不科学,后文会说)。于是,直接想到了去逆向分析那些夜间模式做得好的应用的源代码,学习他们的实现套路。所以,本文的实现思路来自于编写这些应用的夜间模式功能的童鞋,先在这里向他们表示感谢。我的手机里面使用高频的应用不少,其中简书和知乎是属于夜间模式做得相当 nice 的。先给两个效果图大家对比感受下

简书 知乎

如果大家仔细观察,肯定会发现,知乎的切换效果更漂亮些,因为它有一个渐变的效果。那么它们的夜间模式到底是如何实现的呢?别急接着往下看,你也可以。

实现套路

这里先展示一下我的实现效果吧

简书实现效果 知乎实现效果

此处分为两个部分,一部分是 xml 文件中要干的活,一部分是 Java 代码要实现的活,先说 xml 吧。

XML 配置

首先,先写一套UI界面出来,上方左边是两个 TextView,右边是两个 CheckBox,下方是一个 RecyclerView ,实现很简单,这里我不贴代码了。

接着,在 styles 文件中添加两个 Theme,一个是日间主题,一个是夜间主题。它们的属性都是一样的,唯一区别在于颜色效果不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--白天主题-->
<style name="DayTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="clockBackground">@android:color/white</item>
<item name="clockTextColor">@android:color/black</item>
</style>
<!--夜间主题-->
<style name="NightTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/color3F3F3F</item>
<item name="colorPrimaryDark">@color/color3A3A3A</item>
<item name="colorAccent">@color/color868686</item>
<item name="clockBackground">@color/color3F3F3F</item>
<item name="clockTextColor">@color/color8A9599</item>
</style>

需要注意的是,上面的 clockTextColor 和 clockBackground 是我自定义的 color 类型属性

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="clockBackground" format="color" />
<attr name="clockTextColor" format="color" />
</resources>

然后再到所有需要实现夜间模式功能的 xml 布局文件中,加入类似下面设置,比如我在 RecyclerView 的 Item 布局文件中做了如下设置

稍稍解释下其作用,如 TextView 里的 android:textColor=”?attr/clockTextColor” 是让其字体颜色跟随所设置的 Theme。到这里,xml 需要做的配置全部完成,接下来是 Java 代码实现了。

继续阅读全文 »