抖音爬虫教程,AndServer+Service 打造 Android 服务器实现 so 文件调用

so 文件调用

随着 Android 移动安全的高速发展,不论是为了执行效率仍是程序的安全性等,关键代码下沉 native 层已成为基本操做。<br>native 层的开发就是通指的 JNI/NDK 开发,经过 JNI 能够实现 java 层和 native 层(主要是 C/C++ )的相互调用,native 层经编译后产生 so 动态连接库,so 文件具备可移植性广,执行效率高,保密性强等优势。<br>那么问题来了,如何调用 so 文件显得异常重要,固然你也能够直接分析 so 文件的伪代码,利用强悍的编程功底直接模拟关键操做,可是我想对于普通人来讲头发仍是比较重要的。 <br>当前调用 so 文件的主流操做应该是: <br>1,基于 Unicorn 的各类实现(还在学习中,暂且不表)  <br>2,Android 服务器的搭建,在 App 内起 http 服务完成调用 so 的需求(固然前提是过了 so 的效验等操做)<br>至于为何选用 AndServer,好吧,不为何,只是由于搜索到了它  <br>为何结合 Service,在学习 Android 开发的时候了解到了 Service 的生命周期,我的理解用 Service 去建立 Http 服务比较好。 <br>固然也有 Application 的简单使用,由于在正式环境中,大多数 so 文件的逻辑中都有 context 的一些包名了,签名了的效验等,自定义 Application 的话获取 context 传参就行了。java

libyemu.so 简介

这是我编译好的一个 so 文件,就是根据入参作下简单的字符串拼接(如下是 native 层编译前的 c 代码)android

extern "C"
JNIEXPORT jstring JNICALL
Java_com_fw_myapplication_ndktest_NdkTest_stringFromUTF(JNIEnv *env, jobject instance, jstring str_) {
    jclass String_clazz = env->FindClass("java/lang/String");
    jmethodID concat_methodID = env->GetMethodID(String_clazz, "concat", "(Ljava/lang/String;)Ljava/lang/String;");
    jstring str = env->NewStringUTF("  from so --[NightTeam夜幕]");
    jobject str1 = env->CallObjectMethod(str_, concat_methodID, str);
    const char *chars = env->GetStringUTFChars((jstring)str1, 0);
    return env->NewStringUTF(chars);
}

这部分代码仍是有必要贴一下的,简单的静态注册使用了反射的思想,反射在逆向中相当重要<br>接下来是 java 代码,定义了 native 函数编程

package com.fw.myapplication.ndktest;
public class NdkTest {
    public static native String stringFromUTF(String str);
    static {
        System.loadLibrary("yemu");
    }
}

若是到这里有点懵逼的同窗可能须要去补下 Android 开发基础了json

Android 项目测试 so

先说下个人环境,由于这个环境影响太大了  <br>1,AndroidStudio 3.4  <br>2,手机 Android 6 架构 armeabi-v7a  <br>打开 AndroidStudio 新建 project  <br><br>在 module 的 build 中加这么一句,而后 sync  <br><br>把编译好的 so 文件复制到 libs 文件夹下(和刚才的 jniLibs.srcDirs 对应)  <br><br>把 so 对应的 java 代码也 copy 过来,注意包名类名的一致性  <br><br>打开 activity_main.xml 文件为 TextView 添加 id  <br><br>打开 MainActiviy.java 开始编码  <br><br>这两行的意思就是,先从布局中找到对应 id 的 TextView,而后为其设置 Text(调用 native 函数的返回值)  <br>下面测试一下我们的 so 调用状况  <br><br>能够看到我们的 so 文件调用成功(这里我们的 so 没有效验,只是测试 app 是否能够正常调用)<br>浏览器

AndServer 代码编写

AndServer 官方文档:https://yanzhenjie.com/AndServer/  <br>打开官方文档,看看人家的入门介绍,新建 java 文件  <br><br>如图经典 MVC 的 C 就写好了,定义了一个 nightteam_sign 接口,请求方式为 get,请求参数为 sign,调用 native 函数,而后返回 json,可是这里我想利用 Application 获取下 context 对象,取下包名,接下来自定义 Applictaion<br>安全

package com.nightteam.httpso;
import android.app.Application;
public class MyApp extends Application {
    private static MyApp myApp;
    public static MyApp getInstance() {
        return myApp;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        myApp = this;
    }
}

而后在 manifest 文件中指定要启动的 Application  <br><br>而后修改 MyController.java 的代码  <br><br>接下来把官方文档-服务器的代码 copy 下来  <br>导入一些包,修改部分代码以下  <br><br>新版本的 AndServer.serverBuilder 已经须要传递 context 了,这里把网络地址和端口号也修改成从构造参数中获取,到这里 AndServer 的东西基本完了,实际上我们就搭建一个调 so 的接口,并无过多的业务逻辑,因此代码就是使用的最简单的<br>服务器

Service 代码编写

我们这里用按钮的点击事件启动 Service,故在 activity_main.xml 中添加一个 button 并指定点击事件  <br><br><br>接下来编写自定义 Service 代码<br>网络

package com.nightteam.httpso.Service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import com.nightteam.httpso.ServerManager;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class MyService extends Service {
    private static final String TAG = "NigthTeam";
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate: MyService");
        new Thread() {
            @Override
            public void run() {
                super.run();
                InetAddress inetAddress = null;
                try {
                    inetAddress = InetAddress.getByName("0.0.0.0");
                    Log.d(TAG, "onCreate: " + inetAddress.getHostAddress());
                    ServerManager serverManager = new ServerManager(getApplicationContext(), inetAddress, 8005);
                    serverManager.startServer();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

打上了几个 log,在子线程中启动 AndServer 的服务(什么时候使用 UI 线程和子线程是 Android 基础,这里就不赘述了)  <br>注意一下,这里从 0.0.0.0 获取 inetAddress,可不要写错了,localhost 和 0.0.0.0 的区别请移步搜索引擎  <br>而后就是向 ServerManager 的构造函数传递 context,inetAddress,port 用来 new 对象,随后开启服务<br>最后注意检查下 manifest 文件中 Service 的声明  <br>架构

开启 Service,并获取本机 ip

回到咱们的 MainActivity.java 的 operate( button 的点击事件)编写启动 Service 代码app

public void operate(View view) {
        switch (view.getId()){
            case R.id.id_bt_index:
                //启动服务:建立-->启动-->销毁
                //若是服务已经建立了,后续重复启动,操做的都是同一个服务,不会再从新建立了,除非你先销毁它
                Intent it1 = new Intent(this, MyService.class);
                Log.d(TAG, "operate: button");
                startService(it1);
                ((Button) view).setText("服务已开启");
                break;
        }
    }

到这里咱们的服务基本搭建好了,可是为了方便起见,我想把我们的本机 ip 显示在 App 上,这样咱们就不用去设置再查看了  <br>我在网上找到了一个获取 ip 地址的一个工具类,源码以下:

package com.nightteam.httpso;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.regex.Pattern;
public class NetUtils {
    private static final Pattern IPV4_PATTERN = Pattern.compile("^(" +
            "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" +
            "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$");
    private static boolean isIPv4Address(String input) {
        return IPV4_PATTERN.matcher(input).matches();
    }
    //获取本机IP地址
    public static InetAddress getLocalIPAddress() {
        Enumeration<NetworkInterface> enumeration = null;
        try {
            enumeration = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e) {
            e.printStackTrace();
        }
        if (enumeration != null) {
            while (enumeration.hasMoreElements()) {
                NetworkInterface nif = enumeration.nextElement();
                Enumeration<InetAddress> inetAddresses = nif.getInetAddresses();
                if (inetAddresses != null)
                    while (inetAddresses.hasMoreElements()) {
                        InetAddress inetAddress = inetAddresses.nextElement();
                        if (!inetAddress.isLoopbackAddress() && isIPv4Address(inetAddress.getHostAddress())) {
                            return inetAddress;
                        }
                    }
            }
        }
        return null;
    }
}

把工具类 copy 到咱们的 Android 项目中,继续在 MainActivity.java 中编码  <br><br>获取了一下本机地址和 Android SDK 版本( Android 8 以后启动 Service 方式不同)<br>

申请权限,启动 App

最后一步就是为 app 申请网络权限了  <br><br>随后链接咱们的手机,运行项目,测试一下,点击开启服务  <br><br>看下 AndroidStudio 日志  <br><br>好像一切正常,在浏览器访问下试试( ip 就是 App 中显示的 ip 地址)  <br><br>如图正常访问到了咱们想要的内容<br>回过头来讲下 Service,打开咱们手机的设置,找到应用程序管理-运行中的服务(手机不一样,方式不一样)<br><br>能够看到咱们的程序,运行了一个服务,这个服务就是我们编码的 MyService<br><br>接下来杀掉该 App进程,再次查看运行中的服务<br><br>我这里在权限管理设置了自动运行,能够保持服务的运行。(这个地方仍是根据系统有大小差别)<br>至此使用 App 起 http 服务调 so 就完成了

TiToData:专业的短视频、直播数据接口服务平台。 更多信息请联系: TiToData 覆盖主流平台:抖音,快手,小红书,TikTok,YouTube

相关文章
相关标签/搜索