Android

Android ui

控件 #

不讲

布局 #

3种基本布局

  1. LinearLayout
    1. 线性布局,可使用android:orientation来控制排列方向
    2. layout_weight,权重,根据父权进行分配,常配合0dp使用
  2. RelativeLayout
    1. 相对布局,其属相之多,但简单
  3. FrameLayout
    1. 帧布局,不讲,用得少
  • 常见关键字
    • match_parent, 当前控件多的大小和父布局的大小一样
    • warp_content, 当前控件的大小能够刚好好汉里面的内容,由控件内容决定其大小

自定义控件 #

Android 协程-retrofit

导入 #

dependencies {
	implementation 'com.squareup.retrofit2:retrofit:2.6.1'
	implementation 'com.squareup.retrofit2:converter-gson:2.6.1'

}

第一个协程 #

class MainActivity : AppCompatActivity() {  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        setContentView(R.layout.activity_main)  
        getAppDataBtn.setOnClickListener {  
            val retrofit = Retrofit.Builder()  
                .baseUrl("http://10.0.2.2/")  
                .addConverterFactory(GsonConverterFactory.create())  
                .build()  
            val appService = retrofit.create(AppService::class.java)  
            appService.getAppData().enqueue(object : Callback<List<App>> {  
                override fun onResponse(call: Call<List<App>>,  
                                        response: Response<List<App>>) {  
                    val list = response.body()  
                    if (list != null) {  
                        for (app in list) {  
                            Log.d("MainActivity", "id is ${app.id}")  
                            Log.d("MainActivity", "name is ${app.name}")  
                            Log.d("MainActivity", "version is ${app.version}")  
                        }  
                    }  
                }  
                override fun onFailure(call: Call<List<App>>, t: Throwable) {  
                    t.printStackTrace()  
                }  
            })  
        }  
    }  
}

定义接口 #

interface AppService{
	//静态
	@GET("get_data.json")
	fun getData(): Call<Data>
	//动态参数
	@GET("page/{page}/get_data.json")
	fun getPageData(@Path("page") page:Int): Call<Data>
	
	//get 带参数
	@GET("user/login")
	fun login(@Query("username") username:String,@Query("password") password:String): Call<ResponseBody>

	//post
	@POST("user/login")
	fun login(@Body data:Data): Call<ResponseBody>

	//指定静态header呢
	@Header("sign: 123")

	//动态Header
	@POST("user/login")
	fun login(@Header("sign") sign:String,@Body data:Data): Call<ResponseBody>
	
}

论Retrofit构建起的最佳写法 #

先写一个ServiceCretaor单例类

...

Android 比赛

协程,构建,一个MVVM的frame #

先是构建器


object ServiceCreator {  
    private const val BASE_URL="http://124.93.196.45:10001"  
    private val retrofot: Retrofit = Retrofit.Builder()  
        .baseUrl(BASE_URL)  
        .addConverterFactory(GsonConverterFactory.create())  
        .build()  
  
    fun <T> create(serviceClass:Class<T>): T= retrofot.create(serviceClass)  
    inline fun <reified T>create():T= create(T::class.java)  
  
}

然后是接口

interface NewsService {  
    @GET("/prod-api/press/category/list")  
    fun getNewsType(): Call<NewsType>  
  
    @GET("/prod-api/press/press/list")  
    fun getNewsList(@Query("id") id:String,@Query("hot") hot:String):Call<NewsList>  
}

写一个Network

  
object SmartCityNetwork {  
    private val userService= ServiceCreator.create<UserService>()  
    suspend fun login(data: LoginData) = userService.loginService(data).await()  
  
    private val AdvService=ServiceCreator.create<MetroService>()  
    suspend fun getAdv()=AdvService.getAdv().await()  
  
    private val newsService=ServiceCreator.create<NewsService>()  
    suspend fun getNewsType()=newsService.getNewsType().await()  
  
    suspend fun getNewsList(id :String,hot:String)= newsService.getNewsList(id,hot).await()  
  
    private suspend fun <T> Call<T>.await(): T {  
        return suspendCoroutine {  
            enqueue(object : Callback<T> {  
                override fun onResponse(call: Call<T>, response: Response<T>) {  
                    val body = response.body()  
                    if (body != null) it.resume(body)  
                    else it.resumeWithException(RuntimeException("response body is null"))  
                }  
                override fun onFailure(call: Call<T>, t: Throwable) {  
                    it.resumeWithException(t)  
                }  
            }) }  
  
    }  
  
  
}

处理返回数据,其实可以分开写不同的接口

...

android 碎念

安卓 实现卡片

圆角程度 cardCornerRadius 阴影: cardElevation

<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:app="http://schemas.android.com/apk/res-auto"  
    app:cardCornerRadius="20dp"  
    android:layout_marginBottom="20dp"  
    android:layout_height="wrap_content"  
    android:layout_width="match_parent">



</androidx.cardview.widget.CardView>

Android 网络请求

异步get请求


    private fun asyncGet() {
        val url = ""
        //创建request请求对象
        val request = Request.Builder()
            .url(url)
            //.method()方法与.get()方法选取1种即可
            .method("GET", null)
            .build()
 
        //创建call并调用enqueue()方法实现网络请求
        OkHttpClient().newCall(request)
            .enqueue(object : Callback {
                override fun onFailure(call: Call, e: IOException) {
                }
 
                override fun onResponse(call: Call, response: Response) {
                }
            })
    }

异步post请求


    private fun asyncPost() {
        val url = ""
        //添加post请求参数
        val requestBody = FormBody.Builder()
            .add("userName", "name")
            .add("passWord", "pass")
            .build()

		//发送josn
		//var jsonObject = JSONObject()  
	    //jsonObject.put("studentNumber","1713630001")  
	    //jsonObject.put("password","123456")  
	    //val requestBody=jsonObject.toString().toRequestBody("application/json".toMediaType())  

        //创建request请求对象
        val request = Request.Builder()
            .url(url)
            .post(requestBody)
            .build()
 
        //创建call并调用enqueue()方法实现网络请求
        OkHttpClient().newCall(request)
            .enqueue(object : Callback {
                override fun onFailure(call: Call, e: IOException) {
                }
 
                override fun onResponse(call: Call, response: Response) {
                }
            })
    }

post json

...

Android 适配器

由于是安卓原生开发,肯定是少不了写适配器的

考虑到即使是cv也很费时间,所以写一个通用的适配器

class GenericAdapter<T>(
    private val items: List<T>,
    private val layoutId: Int,
    private val bind: (View, T) -> Unit
) : RecyclerView.Adapter<GenericAdapter.GenericViewHolder>() {

    class GenericViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GenericViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(layoutId, parent, false)
        return GenericViewHolder(view)
    }

    override fun onBindViewHolder(holder: GenericViewHolder, position: Int) {
        bind(holder.itemView, items[position])
    }

    override fun getItemCount() = items.size
}

use

需要设置每行的个数 binding.welfareType.layoutManager = GridLayoutManager(requireContext(),2)

val adapter = GenericAdapter(listOf("Item 1", "Item 2"), R.layout.item_layout) { view, item ->
    val textView: TextView = view.findViewById(R.id.textView)
    textView.text = item
}
recyclerView.adapter = adapter

Android-网络请求

依旧是网络请求大头,以最快的方式写

协程 Retrofit #

class Auth(private val token: String) : Interceptor {  
    override fun intercept(chain: Interceptor.Chain): Response {  
        val request =  chain.request()  
            .newBuilder()  
            .addHeader("Authorization","Bearer $token")  
            .build()  
  
        return chain.proceed( request)  
    }  
  
}  
  
fun createRetrofitWithAuth() :Retrofit{  
    return Retrofit.Builder()  
        .baseUrl("http://124.93.196.45:10193/")  
        .addConverterFactory(GsonConverterFactory.create())  
        .build()  
}  
  
  
fun createRetrofitWithAuth(token:String) :Retrofit{  
  
    val client=OkHttpClient.Builder()  
        .addInterceptor(Auth(token))  
        .build()  
  
    return Retrofit.Builder()  
        .baseUrl("http://124.93.196.45:10193/")  
        .addConverterFactory(GsonConverterFactory.create())  
        .client(client)  
        .build()  
}

定义接口

interface ApiService {  
    @GET("/prod-api/api/public-welfare/public-welfare-type/list")  
    suspend fun WelfareType(): WelfareType  
  
    @POST("/prod-api/api/login")  
    suspend fun Login(@Body body:LoginBody): Login  
  
    @GET("/prod-api/api/public-welfare/ad-banner/list")  
    suspend fun Banner(): Banner  
}

viewmodel

...

反编译

签名 #

生成jks文件

keytool -genkeypair -alias ljyhljyh -keypass ljyhljyh -keyalg RSA -keysize 1024 -validity 365 -keystore filename.jks -storepass ljyhljyh

重新签名

jarsigner -verbose -keystore filename.jks -storepass 501937 -signedjar ai3.apk -digestalg SHA1 -sigalg MD5withRSA ai2.apk filename

apktool #

反编译

apktool d apk_name

重新打包

apktool b 文件 -o apk_name

flutter

起因 #

放假在家闲的皮爆,有空学习写了个(其实在很久之前就有打算了) 因为网易云音乐下载有很多但是加密的,虽然可以解密,但是也不方便管理,所以就有了这个软件,可以嵌入元数据(mp3和flac),包括歌词封面等。同步网易云歌单,可以删除本地文件

开发 #

至于学习flutter,最开始知道flutter是因为逆向系列了解到的,听说写ui很方便,之前也有用过java开发。java的语法还也不是很喜欢。 网易云的api 参考: NeteaseCloudMusicApi

学习编程语言我不是很喜欢看视频来,慢得很,需要什么直接去搜代码就行了。 先看看官方的文档,demo,自己需要什么功能直接百度 虽然可能了解不深刻,但是跟着视频写代码更烦人

使用 #

设置里面要先设置cookie,只需要cookie中的MUSIC_U的部分,以及保存路径,这个保存路径是歌单的保存路径,如果下载的话会根据歌单名为文件夹保存在下级。

元数据默认嵌入所有

先根据歌单id获取歌曲,若要下载需要收藏歌单,下载完成会检测本地歌单中多余歌曲并徐闻是否删除。

似乎就这点鸟功能