Zacharia2 / WebDav-App

为安卓设备开放提供一个文件访问端口(在线文件服务)
MIT License
1 stars 0 forks source link

deps #1

Open Zacharia2 opened 1 week ago

Zacharia2 commented 1 week ago

implementation("com.ettrema:milton-api:1.8.1.4")

Zacharia2 commented 1 week ago

implementation("io.milton:milton-server-ce:4.0.2.2101")

Zacharia2 commented 1 week ago

使用viewflow或者使用material2

https://m2.material.io/components/app-bars-bottom/android

Zacharia2 commented 1 week ago

在Java中,你可以使用static final关键字来定义常量。对于上面的例子,我们可以为每个位掩码定义一个常量,这样代码会更容易阅读和维护。以下是如何定义这些常量的示例:

public class NetworkUtils {
    // 定义位掩码常量
    public static final int MASK_WIFI = 0x01; // 0000 0001
    public static final int MASK_ETHERNET = 0x02; // 0000 0010
    public static final int MASK_MOBILE = 0x04; // 0000 0100
    public static final int MASK_LOOPBACK = 0x08; // 0000 1000
    public static final int MASK_BLUETOOTH_PAN = 0x10; // 0001 0000
    public static final int MASK_WLAN = 0x20; // 0010 0000
    public static final int MASK_ALL = 0xFF; // 1111 1111

    // 其他方法...
}

在上面的代码中,0x010x020x040x080x100x200xFF是十六进制表示法,它们分别对应于二进制的0000 00010000 00100000 01000000 10000001 00000010 00001111 1111。这些值被赋给常量,以表示不同的网络接口类型。

现在,你可以在原来的代码中使用这些常量,而不是直接使用数字:

ArrayList<String> retValue = new ArrayList<>();
try {
    String wifiAddr = getWifiIpAddress(context);
    if ((mask & MASK_WIFI) == MASK_WIFI && wifiAddr != null) {
        retValue.add(wifiAddr);
    }
    Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
    while (en.hasMoreElements()) {
        NetworkInterface intf = en.nextElement();
        if (((mask & MASK_ETHERNET) == MASK_ETHERNET && intf.getDisplayName().startsWith("eth")) ||
            ((mask & MASK_MOBILE) == MASK_MOBILE && (intf.getDisplayName().startsWith("pdp") || intf.getDisplayName().startsWith("rmnet"))) ||
            ((mask & MASK_LOOPBACK) == MASK_LOOPBACK && intf.getDisplayName().startsWith("lo")) ||
            ((mask & MASK_BLUETOOTH_PAN) == MASK_BLUETOOTH_PAN && intf.getDisplayName().startsWith("bt-pan")) ||
            ((mask & MASK_WLAN) == MASK_WLAN && intf.getDisplayName().startsWith("wl")) ||
            mask == MASK_ALL) {
            Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses();
            while (enumIpAddr.hasMoreElements()) {
                InetAddress inetAddress = enumIpAddr.nextElement();
                if (inetAddress instanceof Inet4Address) {
                    String ipAddr = inetAddress.getHostAddress().toString();
                    if (wifiAddr == null || !wifiAddr.equals(ipAddr)) {
                        retValue.add(ipAddr);
                    }
                }
            }
        }
    }
} catch (SocketException ex) {
    ex.printStackTrace();
}
return retValue;

使用常量可以使代码更清晰,更易于理解,并且如果将来需要修改掩码值,你只需在一个地方进行更改,而不必在代码库中搜索并替换所有出现的数字。

Zacharia2 commented 1 week ago

我已经查看了您提供的链接中的源代码。以下是需要在该代码中使用的权限:

  1. INTERNET:用于访问互联网。
  2. ACCESS_NETWORK_STATE:用于检查网络连接状态。
  3. ACCESS_WIFI_STATE:用于获取Wi-Fi状态信息。
  4. CHANGE_WIFI_STATE:用于改变Wi-Fi状态,例如开启或关闭Wi-Fi。
  5. CHANGE_NETWORK_STATE:用于改变网络连接状态。

这些权限需要在AndroidManifest.xml文件中声明,并且如果您的应用目标API级别是23或以上,还需要在运行时请求这些权限。

以下是权限声明的示例:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xinglan.webdavserver">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />

    <!-- 其他权限和组件声明 -->

</manifest>

请确保在代码中适当地检查和请求这些权限。

Zacharia2 commented 1 week ago

AndroidX 是一个开源库的集合,它为Android开发者提供了一套向后兼容的Jetpack组件库。这些库是Android支持库(Support Library)的替代品,旨在提供更加一致、功能丰富且易于使用的API,以便开发者能够更容易地构建优秀的Android应用程序。

以下是AndroidX的一些关键点:

  1. 向后兼容性:AndroidX库设计用于向后兼容,这意味着使用AndroidX库的应用程序可以在旧的Android版本上运行,而不会丢失任何功能。

  2. Jetpack组件:AndroidX是Jetpack的一部分,它包含了Jetpack中的许多组件,例如LiveData、ViewModel、Room、Navigation、WorkManager等。

  3. 重构的包名:与Android支持库不同,AndroidX库的包名已经重构,不再使用android.support前缀。新的包名以androidx开头,例如androidx.appcompatandroidx.recyclerview等。

  4. 统一的版本管理:AndroidX库使用统一的版本号,这使得依赖项管理变得更加简单。开发者只需为所有AndroidX库指定一个版本号,而不是为每个单独的库指定。

  5. 持续更新和改进:AndroidX库会定期更新,以包含最新的功能和修复,确保开发者能够利用最新的Android平台特性。

  6. 迁移工具:Google提供了迁移工具,帮助开发者将现有的项目从Android支持库迁移到AndroidX。

为什么要使用AndroidX?

为了开始使用AndroidX,你需要在项目的build.gradle文件中进行一些配置,并可能需要迁移现有的代码库。Google提供了详细的迁移指南来帮助开发者完成这一过程。

Zacharia2 commented 1 week ago

是的,这段代码中使用了一些过时的方法和API。以下是对这段代码的更新,以使用最新的Android通知API(基于Android API level 26及以上):

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Build;

private void showNotification(String className, int notificationTextId, int notificationIconId, int notificationStartedTitleId, int notificationStartedTextId, String ipDetail, boolean startForeground) {
    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    String channelId = "your_channel_id"; // 创建通知渠道时使用的ID
    String channelName = "Your Channel Name"; // 用户可见的通知渠道名称

    // 创建通知渠道(仅在Android O及以上版本需要)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT);
        notificationManager.createNotificationChannel(channel);
    }

    Intent startIntent = new Intent();
    startIntent.setClassName(this, className);
    startIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, startIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);

    Notification.Builder builder = new Notification.Builder(this, channelId)
            .setTicker(getString(notificationTextId))
            .setContentTitle(getString(notificationStartedTitleId))
            .setContentText(ipDetail)
            .setSmallIcon(notificationIconId)
            .setContentIntent(pendingIntent)
            .setStyle(new Notification.BigTextStyle().bigText(ipDetail))
            .setAutoCancel(true);

    Notification notification = builder.build();

    if (startForeground) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForeground(NOTIFICATION_STARTED_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
        } else {
            startForeground(NOTIFICATION_STARTED_ID, notification);
        }
    } else {
        notificationManager.notify(1, notification);
    }
}

请注意以下几点更改:

  1. 使用了Notification.Builder来构建通知。
  2. 添加了创建通知渠道的代码,这在Android O(API level 26)及以上版本是必需的。
  3. 使用了NotificationChannel类来创建通知渠道。
  4. 在调用startForeground方法时,如果API版本大于等于Android O,则可以使用ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE参数。
  5. 移除了notification.flags |= 34;这行代码,因为通知的行为可以通过Notification.Builder设置,例如使用.setAutoCancel(true)来让通知在点击后自动取消。

请根据您的具体需求调整channelIdchannelName

Zacharia2 commented 1 week ago

在提供的代码中,我已更新了主要的API以使用最新的通知构建方法。然而,还有一些其他的小细节和最佳实践可以考虑:

  1. 使用NotificationCompat.Builder来支持更广泛的Android版本: 如果你需要支持低于API level 26的Android版本,应该使用NotificationCompat.Builder而不是Notification.Builder

  2. 设置正确的标志: 之前使用的notification.flags |= 34;包含了Notification.FLAG_SHOW_LIGHTSNotification.FLAG_AUTO_CANCEL。现在,这些可以通过Notification.Builder设置。

  3. 使用startForeground的第三个参数: 在Android O及以上版本,startForeground方法可以接受一个额外的参数,表示前台服务的类型。

下面是进一步更新后的代码示例,使用NotificationCompat.Builder来兼容旧版本:

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;

private void showNotification(String className, int notificationTextId, int notificationIconId, int notificationStartedTitleId, int notificationStartedTextId, String ipDetail, boolean startForeground) {
    Context context = getApplicationContext();
    NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    String channelId = "your_channel_id"; // 创建通知渠道时使用的ID
    String channelName = "Your Channel Name"; // 用户可见的通知渠道名称

    // 创建通知渠道(仅在Android O及以上版本需要)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT);
        notificationManager.createNotificationChannel(channel);
    }

    Intent startIntent = new Intent();
    startIntent.setClassName(context, className);
    startIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, startIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);

    NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId)
            .setTicker(getString(notificationTextId))
            .setContentTitle(getString(notificationStartedTitleId))
            .setContentText(ipDetail)
            .setSmallIcon(notificationIconId)
            .setContentIntent(pendingIntent)
            .setStyle(new NotificationCompat.BigTextStyle().bigText(ipDetail))
            .setAutoCancel(true);

    Notification notification = builder.build();

    if (startForeground) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForeground(NOTIFICATION_STARTED_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
        } else {
            startForeground(NOTIFICATION_STARTED_ID, notification);
        }
    } else {
        NotificationManagerCompat.from(context).notify(1, notification);
    }
}

请确保你已经在你的项目中添加了androidx.core:core库,因为NotificationCompat是AndroidX库的一部分。如果你的项目还没有迁移到AndroidX,你需要使用android.support.v4.app.NotificationCompat代替androidx.core.app.NotificationCompat

此外,请确保在AndroidManifest.xml中正确声明了服务以及任何需要的权限。

Zacharia2 commented 1 week ago

implementation("xerces:xercesImpl:2.12.2")