概述

移动端 APP 的热修复技术已经出来了很多年,Android 方面的解决方案也有很多(iOS 已经被苹果官方叫停),比如手淘的 Sophix,微信的 Tinker 等等,他们都能做到代码修复、资源修复以及 SO 文件修复,这里的「修复」也即意味着「替换」。在接入细节、即时生效或者性能损耗等等的一些方面上,两者存在着一些差异,我们这里不做探讨,本文主要关注的是类文件是如何被替换的并且给出一个简易的实现方案。

原理

目前实现代码修复主要有两种方式:native 底层替换和类加载替换。

前者的特点是修复粒度小,但有稳定性问题(Sophix 已解决),局限性在于不适用于类结构发生变化的修改和修复了的非静态方法被反射调用,它的优点是能即时生效。原理是通过对底层的 ArtMethod 结构体进行完整替换来实现。

后者的特性是修复粒度大,稳定性和兼容性较好,但改动需要冷启动才能生效。原理是在 APP 重新启动后让类加载器 Classloader 去加载新替换的类来实现改动。本文的热修复就是这种思路来实现。

那么问题来了,Android 中的类加载器是什么呢?

Read more »

概述

通过上述三篇文章的学习,我们初步掌握了 JNI 的编程方式。
下面重新复习一下 Java 代码调用本地函数的步骤,如下:

将需要本地实现的 Java 方法加上 native 声明;
使用 javac 命令编译 Java 类;
使用 javah 命令生成头文件;
在本地代码中实现头文件中声明的 native 方法;
编译本地代码,生成动态链接库
在 Java 类中加载动态链接库病调用 native 方法。

前面我们都通过 gcc 来生成动态链接库,可以看见生成步骤比较复杂,而在 Android 中我们就要借助 NDK 的帮助,Android NDK 是 Google 提供的开发工具集,通过它能让我们在 Android 中开发出具有 JNI 机制的应用。而新版的 NDK 使用了 GradleCMake 来帮助我们简化了一些步骤,比如手动生成头文件。

Read more »

概述

前面两篇文章的示例代码的主程序都是用 Java 代码编写的,我们看到了如何在 Java 代码中使用 JNI 的方式调用 C 函数。下面我们将学习如何在由 C/C++ 编写的主程序中来运行 Java 类。

我们知道由 Java 类编译生成的字节码需要运行在 Java 虚拟机上,那么在 C/C++ 中运行 Java 代码也需要虚拟机环境吗?答案是肯定的。JNI 为这种情况提供了一套 Invocation API ,它允许本地代码在自身内存区域内加载 Java 虚拟机。编写并运行 Java 代码的 java 命令是由 C 语言编写的,它也是通过 Invocation API 来接收命令参数。

除此之外, Android 系统的 dalvikvm 虚拟机的主入口( dalvikvm-dalvik/dalvikvm/main.c )也是通过 Invocation API 进行工作的。在 Android 启动时, app_process 调用 JNI invocation API 在自身程序域内加载 dalvikvm 虚拟机,而后调用 ZygoteInit 类的 main() 方法,从而运行 Zygote 进程。

Read more »

概述

在上一篇的文章中,我们学会了在 Java 层如何通过 JNI 来调用 C 层的代码,这一篇文章我们将看一下如何在 C 层控制 Java 层的代码,主要包含以下内容:

  1. 创建 Java 对象
  2. 访问类静态成员域
  3. 调用类的静态方法
  4. 访问 Java 对象的成员变量
  5. 访问 Java 对象的方法

功能描述

我们下面要实现一个 Java 层与 C 层相互调用的混编程序,调用流程如下图:

Read more »

概述

Android 系统架构中包含了 Applications (应用程序层)、Application framework(应用程序框架层)、Libraries + Android runtime(系统运行库层)以及 Linux Kernel(Linux核心层)。从编程语言的角度看,每层的功能模块都是使用相应的语言编写的,在此过程中,C/C++ 与 Java相互通信时就需要一个媒介来联系起来,JNI(Java Native Interface) 就充当了这一角色,它允许 Java 代码和 基于 C/C++ 编写的应用程序、模块、库进行交互操作。

Read more »

前言

  • 本文假定读者已经安装并配置好了相应的开发环境: Gradle 、 Android SDK 、 Android NDK 及Android Studio等。
  • 通过源码编译我们可以进行定制化改造和修正bug:譬如华为7.0上的边缘滑动崩溃问题。
  • 阅读正文将花费您大约3分钟。

创建 Android 工程

虽然官方已经不再推荐 Android 命令行工具创建项目,我们还是瞄一眼它的命令格式:

1
2
android create project --target android-22 --name MyRNApp --path /home/doslin/blog/MyRNApp 
--activity MyActivity --package com.doslin.rnapp

运行后会提示:

The android command is no longer available.

For manual SDK and AVD management, please use Android Studio.

For command-line tools, use tools/bin/sdkmanager and tools/bin/avdmanager

Read more »

前言

  • 文中所有 RN 缩写指代React Native For Android
  • 分析的 RN 代码基于
1
2
3
4
{
"react": "15.4.1",
"react-native": "0.39.2"
}
  • 本文主要分析 Java 层实现,对 C++ 和 JS 笔墨较少。
  • 阅读正文将花费您大约20分钟。

背景

公司内几个 APP 已经接入并上线了多个 RN 模块,后续规划的定制化需求及性能优化需要我们对 RN 底层原理有更深入的理解。下面通过研读源代码来分析和总结下 Android 中的 RN 实现原理。

从示例入手

之前写过一篇弹射起步:Android原生项目集成React Native模块

示例代码如下:

1
2
3
4
5
6
public class MainActivity extends ReactActivity {
@Override
protected String getMainComponentName() {
return "RN_Demo";
}
}

可以发现 RN 容器外层本质也是一个 Activity ,继承了 ReactActivity ,需要我们覆写 getMainComponentName() 方法,更改其返回值为组件名。

Read more »

前言

  • 以下内容不牵涉 Git 的内部实现原理,阅读正文将花费您大约15分钟。
  • 文中的所有 Git 命令省略了参数,完整调用请查阅官方文档。
  • 本文基于一次组内分享的内容整理,希望对各位有所帮助。

作为开发者,使用 Git 作为项目的代码控制系统已经是必备技能了(当然,还有本文的MarkDown),而日常工作中的你是否只停留在无尽的 pullpush 中呢?

下面就来介绍 Git 中的几种实用命令,相信会对你今后可能遇到的实际工作场景带来实质性的效率提升。

介绍命令之前,首先我们先需要了解下 Git 中操作区域的概念。

操作区域

Git 的操作区域和 vi 中的缓冲区的概念很类似,不同的 Git 命令会在不同的操作区域中工作。

操作区域

如图所示,Git的 add 操作会将文件的修改记录保存在暂存区,之后进行的 commit 操作会将暂存区的修改内容全部提交到历史区,最后进行的 push 操作将会把本地的操作记录推送到远程仓库中去。
之所以此处远程库的背景色使用了暗色调,是因为推送到远程库的代码是需要你“负责”的,一旦发布即是历史的诞生,请对 push 的操作保持敬畏和责任感。同时这里也牵涉到 Git 中提交哲学的概念。

Read more »


说明和前提

1、由于通过命令react-native init初始化的React Native(以下简称RN)项目结构与原生项目有区别,所以不能单纯直接在已有项目的根目录下运行该命令。

2、RN需要Android4.1或以上的环境,故集成RN的Android项目的minSdkVersion需设置为API16或以上。

3、本机安装NPM支持:
新版的RN依赖都将发布在NPM(包管理工具,如同Maven仓库)中,故需安装NPM。

4、本文安装环境为MAC,Windows或Linux上的命令差异请参考官方文档

集成步骤

1. 安装NPM

之后于同时需要NodeJS服务器,故只需安装NodeJS,NPM会随同安装。

1
2
brew install node
brew install watchman
Read more »
0%