PS:背景需求来自Andorid移动端访问Window共享文件夹
工具:
Unity2018.4.36f1 AS2020.3
smbj-0.11.3.jar
slf4j-api-1.7.25.jar
mbassador-1.3.0.jar
jcifs-1.3.19.jar
bcprov-jdk15on-1.69.jar
asn-one-0.5.0.jar
什么是smb协议
SMB 一种客户机/服务器、请求/响应协议。通过 SMB 协议,客户端应用程序可以在各种网络环境下读、写服务器上的文件,以及对服务器程序提出服务请求。此外通过 SMB 协议,应用程序可以访问远程服务器端的文件、以及打印机、邮件槽(mailslot)、命名管道(named pipe)等资源
打开smb协议
控制面板-程序-启用或关闭Window功能-勾选SMB 1.0/CIFS 文件共享与支持
开启共享文件夹
开启访问权限:
控制面板--网络和Internet--网络和共享中心--高级共享设置
SMBFile流
建立文件流连接
SmbFile remoteFile = new SmbFile("smb://192.168.1.XXX/Test/"); //可以是文件夹或文件
读文件流:
SmbFileInputStream inputStream = new SmbFileInputStream("smb://192.168.1.XXX/Test/a.txt");
写文件流: SmbFileOutputStream outputStream =new FileOutputStream(filePath);//filepath=remoteFile.getpath()获取
//localDir保存到本地文件夹路径
public static void smbGet(String remoteUrl, String localDir)
{
InputStream in = null;
OutputStream outputStream = null;
try {
SmbFile remoteFile = new SmbFile(remoteUrl);
if (remoteFile == null) {
return;
}
String fileName =remoteFile.getName();
int length = remoteFile.getContentLength();// 得到文件的大小
byte buffer[] = new byte[length];
SmbFileInputStream inputStream = new SmbFileInputStream(remoteFile); // 建立smb文件输入流
while ((inputStream.read(buffer)) != -1)
{
System.out.write(buffer);
}
inputStream.close();
File localFile = new File(localDir + File.separator+fileName );
try {
//向文件中写入字节数组
String fileSavePath=localFile.getPath();
outputStream = new FileOutputStream(fileSavePath);
outputStream.write(buffer);
outputStream.flush();
//关闭此文件输出流并释放与此流有关的所有系统资源。此文件输出流不能再用于写入字节。 如果此流有一个与之关联的通道,则关闭该通道。
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
catch(Exception e)
{
}
}
if (smbFile.isDirectory()) //判断remoteUrl是否是文件夹
{
}
if (smbFile.isFile()) //判断remoteUrl是否是文件
{
}
//往远程共享目录写入文件,如txt 、Json等
//SmbFile smbFileOut = new SmbFile("smb://192.168.1.xxx/Test/bb.txt");
public static void smbWriteFilesToRemote(String remoteUrl,String data)
{
try
{
SmbFile smbFileOut = new SmbFile(remoteUrl);
if(!smbFileOut.exists())
smbFileOut.createNewFile();
SmbFileOutputStream outputStream = new SmbFileOutputStream(smbFileOut);
outputStream.write(data.getBytes());
outputStream.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
AS打包aar
如果不会打包aar,可以参看我的上一篇文章 AS打包aar
最后Unity编译APK以及调用aar
附:
build.gradle
plugins {
id 'com.android.library'
id 'kotlin-android'
}
android {
compileSdk 30
defaultConfig {
minSdk 21
targetSdk 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation files('libs\\asn-one-0.5.0.jar')
implementation files('libs\\bcprov-jdk15on-1.69.jar')
implementation files('libs\\jcifs-1.3.19.jar')
implementation files('libs\\mbassador-1.3.0.jar')
implementation files('libs\\slf4j-api-1.7.25.jar')
implementation files('libs\\smbj-0.11.3.jar')
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
//如果引入了Unity class.jar并且Add Library
//默认是false获取设备内存,true获取到是内存卡
public static String getStoragePath(boolean is_removale) {
StorageManager mStorageManager = (StorageManager) (UnityPlayer.currentActivity.getApplicationContext()).getSystemService(Context.STORAGE_SERVICE);
Class<?> storageVolumeClazz = null;
try {
storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
Method getPath = storageVolumeClazz.getMethod("getPath");
Method isRemovable = storageVolumeClazz.getMethod("isRemovable");
Object result = getVolumeList.invoke(mStorageManager);
final int length = Array.getLength(result);
for (int i = 0; i < length; i++) {
Object storageVolumeElement = Array.get(result, i);
String path = (String) getPath.invoke(storageVolumeElement);
boolean removable = (Boolean) isRemovable.invoke(storageVolumeElement);
if (is_removale == removable) {
return path;
}
}
} catch (Exception e) {
return "error";
}
return null;
}
常见报错:
1: java.lang.RuntimeException: java.lang.RuntimeException: Duplicate class bitter.jnibridge.JNIBridge found in modules 2018classes.jar (:app-debug:) and unity-classes.jar (unity-classes.jar)
说明aar包中有重复的unity class.jar应该删除掉,直接用在压缩软件里打开aar删除即可(无须解压)
2: CommandInvokationFailure: Gradle build failed.
C:\Program Files\Java\jdk1.8.0_281\bin\java.exe -classpath "C:\Program Files\Unity\Hub\Editor\2018.4.36f1\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\gradle\lib\gradle-launcher-5.1.1.jar" org.gradle.launcher.GradleMain "-Dorg.gradle.jvmargs=-Xmx4096m" "assembleRelease"
这种报错分很多,应继续往下看错误详情。如果是上面的则是class.jar重复
如果是
Program type already present: com.example.empowerapplication.BuildConfig
java.lang.RuntimeException: java.lang.RuntimeException: com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives:
Learn how to resolve the issue at https://developer.android.com/studio/build/dependencies#duplicate_classes.
Program type already present: com.example.empowerapplication.BuildConfig
说明Unity包名不应该和Unity里manifest.xml的包名重复