0.前言

前几天看大佬给自己网站套了一个APP,看起来很有意思,于是决定自己也整一个。由于自己比较菜,整出来的肯定不如大佬好。

实际上套壳APP并不复杂,实际上是利用Android系统的webview来展示网页,所以首先有一个可以在手机浏览器端工作良好的网页可以套,这里我套的是https://m.dogcraft.top,misskey对移动端的适配确实不错,平时在手机端上都是直接那Firefox浏览的。

开发Android套壳应用有很多途径,既可以用原生的Android工具链直接用Java或者Kotlin来安排,也可以利用RN这样的框架来安排,还可以利用其他的生成器之类的。这些方式各有利弊,原生Android工具链需要用Java或kotlin,这个都不会啊,用第三方的生成器没有灵魂,而且存在安全性的问题,最后决定用React Native,这个是用JavaScript的,之前JavaScript好歹会一点点后来的事实证明会的这一点点完全没有卵用 ( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃

实践证明利用RN搞套壳应用还是很快的,仅仅用了两天的时间就整了个勉强能用的套壳APP(其中多半天在配置Android开发环境,多半天在画启动图)。

零基础的解释:从零搭建Android开发环境、从零开始用React、完全不会kotlinJava、不懂ES6

1.配置开发环境

搭建环境难,是所有步骤里面最难的一部分,可以按照文档里的Android开发环境搭建来安排,上面的一些说法可能有些过时了,具体的内容要根据实际的开发环境来安排。比如Android Studio的安装,实际上在国内(我这里)是完全可以正常下载的,不需要用什么奇奇怪怪的工具,而且用ubuntu的可以直接通过snap来安装。

$ snap list android-studio 
Name            Version  Rev  Tracking       Publisher     Notes
android-studio  4.0.1.0  91   latest/stable  snapcrafters  classic

下面是几个文档上没提到的注意事项

在Android Studio内安装各种组件的时候可以用内置的自动化代理来提速,在设置里面就有,仔细找一找很容易找得到,我是用的mirrors.neusoft.edu.cn:80这一个代理,速度很快。

还有不要忘记安装安装react-native-cli我就是所有都搞完了最后运行react-native start的时候说找不到命令……

sudo cnpm install -g react-native-cli

还有就是yarn可以换成淘宝镜像来提速

yarn config set registry http://registry.npm.taobao.org/

如果连接Android设备调试的时候遇到adb版本问题,可以尝试卸载之前自行安装的adb工具(如果有的话)

实践证明,如果手机开了USB调试,直接插上usb数据线就行了,用不到改udev那一套东西,如果连不上开发服务器,很有可能是adb版本的问题。正确的版本应该在随着Android studio安装的Android SDK里面。

第一次运行yarn react-native run-android会特别慢,也是整个过程中最艰难的环节之一。运行之前记得安装手机,手机上显示通过usb安装应用的时候要及时点击同意。

如果一切正常手机上就会有应用了。

最后就是不要忘了运行react-native start,否则会手机端红屏报错。

2.安排webview

webview要安装一个react-native-webview


 yarn add react-native-webview

react-native link react-native-webview

然后在App.js里面引入这个东西。

import {WebView} from 'react-native-webview';

最后安排在渲染界面的地方。

<View style=
              flex( 1,
              backgroundColor: 'rgba(15,75,120,1)'
            )>
              <WebView
            source= uri( 'https://m.dogcraft.top' )
            style= width( '100%', height: '100%' )
            ref="webView"
            onNavigationStateChange={this.onNavigationStateChange}
          />
          </View>

其中onNavigationStateChange={this.onNavigationStateChange是为了解决返回问题的。

如果一切正常,运行yarn react-native run-android之后应该可以正常使用了,然而会面临一个问题,在手机上按下返回键的时候会直接退出应用而不是回到网页的上一层。这个问题网上已经有了成熟的解决方案,多试几次应该会解决。

import React, {Component} from 'react';
import {
    StyleSheet,
    View,
    Text,
    TouchableOpacity,
    Linking,
    Alert,
    Button,
    ToastAndroid
} from 'react-native'
import SplashScreen from 'react-native-splash-screen';
import { Platform, BackHandler } from 'react-native';
import {WebView} from 'react-native-webview';

export default class example extends Component {

    componentDidMount() {
      setTimeout(SplashScreen.hide,2000)
      if (Platform.OS === 'android') {
        BackHandler.addEventListener('hardwareBackPress', this.onBackAndroid);
      }
    }
    onNavigationStateChange = navState => {
      this.setState({
        backButtonEnabled: navState.canGoBack
      });
    };
    reloaddog =() =>{
      this.refs['webView'].reload();
    }
    
      onBackAndroid = () => {
        //  官网中描述:backButtonEnabled: false,表示webView中没有返回事件,为true则表示该webView有回退事件
        if (this.state.backButtonEnabled) {
          this.refs['webView'].goBack();
          return true;
        } else {
         if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
            //最近2秒内按过back键,可以退出应用。
            return false;
          }
          this.lastBackPressed = Date.now();
          ToastAndroid.show('再按一次退出应用', ToastAndroid.SHORT);
          return true;
        }
      };

    render() {
        return (
            <View style=
              flex( 1,
              backgroundColor: 'rgba(15,75,120,1)'
            )>
              
              <WebView
            source= uri( 'https://m.dogcraft.top' )
            style= width( '100%', height: '100%' )
            ref="webView"
            onNavigationStateChange={this.onNavigationStateChange}
          />
          </View>
        )
    }

}

3.添加APP启动图

这一步骤比较麻烦了,这涉及到Java部分了,而且安装也比较麻烦。

启动图的安装与配置比较麻烦,而且相关说明与现实情况出现了较大的偏离,不过可以根据给出的例子对照自己的项目一点点的摸索。

yarn add react-native-splash-screen

react-native link react-native-splash-screen

运行完 react-native link react-native-splash-screen还要再改好几个地方,按照上面所说的继续安排下去会报错的。

要改的几个地方(包括但不限于)

MainActivity.java 里面加上这个

 @Override
  protected void onCreate(Bundle savedInstanceState) {
      SplashScreen.show(this);  // here
      super.onCreate(savedInstanceState);
  }

还要看一下几个java文件里面有没有import org.devio.rn.splashscreen.SplashScreen;

实际上确保`里面有import org.devio.rn.splashscreen.SplashScreenReactPackage;之后不需要往MainApplication.java`里面添加任何东西了。

然后在android/app/src/main/res/layout/launch_screen.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:orientation="vertical"
              android:gravity="center"
              android:background="#F0F0F0" >
    <ImageView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:src="@drawable/launch_screen" />  
</LinearLayout>

把图片放到android/app/src/main/res/drawable-xxhdpi/launch_screen.pngandroid/app/src/main/res/drawable-xhdpi/launch_screen.png里面。样式在android/app/src/main/res/layout/launch_screen.xml里面调整。

4.改图标名称以及版本号

名称在android/app/src/main/res/values/strings.xml里面改。

包名称以及版本号在android/app/build.gradle里面

defaultConfig {
        applicationId "cn.dogcraft.apk"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName "1.1"
    }

图标在android/app/src/main/res

使用生成工具直接替换就行,我是用的这一个https://icon.wuruihong.com/

这个启动图要收费的,没必要,自己画一个就完事了。

5.打包apk

按照说明一步一步来就行了。

就是android/app/build.gradle这里改的的东西不好找

android {
    compileSdkVersion rootProject.ext.compileSdkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    defaultConfig {
        applicationId "cn.dogcraft.apk"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName "1.1"
    }
    splits {
        abi {
            reset()
            enable enableSeparateBuildPerCPUArchitecture
            universalApk false  // If true, also generate a universal APK
            include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
        }
    }
    signingConfigs {



        release {
            if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
                storeFile file(MYAPP_RELEASE_STORE_FILE)
                storePassword MYAPP_RELEASE_STORE_PASSWORD
                keyAlias MYAPP_RELEASE_KEY_ALIAS
                keyPassword MYAPP_RELEASE_KEY_PASSWORD
            }
        }


        debug {
            storeFile file('debug.keystore')
            storePassword 'android'
            keyAlias 'androiddebugkey'
            keyPassword 'android'
        }
    }
    buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }
        release {
            // Caution! In production, you need to generate your own keystore file.
            // see https://reactnative.dev/docs/signed-apk-android.
            signingConfig signingConfigs.debug
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }

6.效果展示

APP 下载地址