I need to connect from my Android phone to a Windows PC share and access files. I saw some sample apps in Android market that access share folders using smb/samba. But I have no idea about how to create an app like that. Thanks a lot.
You need to get JCIFS and use SmbFile class to interact with files over the network,
http://lists.samba.org/archive/jcifs/2007-September/007465.html
that is a quick example of how to list files, of coarse you need internet permission on. So Far though everytime I try to call SmbFile.listFiles(); I get an UnknownHostException, However others seam to be able to do it with no problem, this might work for you, try it!
Google has released a simple, free Samba client. It is on github so you can have a look and use whatever you need out of that: https://github.com/google/samba-documents-provider
The other option is JCIFS: https://jcifs.samba.org/. There you can find the library and examples on how to use it.
I used JCIFS. Here is an example from my code which reads files from a folder in a windows share:
TreeMap<Date, String> filesInfo = new TreeMap<Date, String>();
NtlmPasswordAuthentication auth = null;
UniAddress dc = UniAddress.getByName(m_dataHostIp);
if(m_userName.length() > 0 && m_password.length() > 0)
auth = new NtlmPasswordAuthentication(m_domain + ";" + m_userName + ":" + m_password);
else
auth = new NtlmPasswordAuthentication(m_domain, null, null);
SmbSession.logon(dc, auth);
SmbFile file = new SmbFile(m_foldername, auth);
SmbFile[] files = file.listFiles();
for (int i = 0; i < files.length; i++)
{
String fileName = files[i].getName();
String extension=fileName.substring(fileName.lastIndexOf(".") + 1);
logInfo(TAG + " " + fileName + "\n");
Date fileTime = new Date(files[i].getDate());
if(m_fileExtension.contains(extension))
filesInfo.put(fileTime, fileName);
}
The code posted above works. It allows you to connect to the share, authenticate (username and password that you know) and get the list of the files. At the root of jcif file access is the SmbFile which has all the info you need to access files in the share. All you need is in your build.gradle for the app add:
dependencies {
implementation files('libs/jcifs-1.3.19.jar')
}
and in your implementation file:
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbFile;
import static jcifs.smb.SmbFile.FILE_SHARE_DELETE;
import static jcifs.smb.SmbFile.FILE_SHARE_READ;
import static jcifs.smb.SmbFile.FILE_SHARE_WRITE;
Related
I created and published a game for android with AndEngine three years ago. Now I am preparing the game again with unity. When I send an update, all of the old data is deleted. Because Unity using 'PlayerPrefs' and Android using 'SharedPreferences'.
So, How do I read old data with Unity?
Here is my old code setup:
private SharedPreferences data;
private SharedPreferences.Editor editor;
// ======================================================================
public void setup(Activity activity) {
data = activity.getSharedPreferences("kayit", 0);
editor = data.edit();
}
I don't think its going to be easy accessing persistent data saved with a different engine - but a solution I can see is release an update with the old engine that will upload the data to a remote server, and then download it using Unity, but since you already released the unity version that might not work for you
PlayerPrefs and SharedPreferences are different things.
But there is a solution.
Unity allows to add native android Java or C++ code to your Unity project and use interfaces to access that code.
So you can write some code using Android SDK/NDK methods to access your SharedPreferences and add it as JAR or AAR to your Unity project.
Read about it in the official documentation https://docs.unity3d.com/Manual/PluginsForAndroid.html
private void ReadAndroidSharedPreferences(string packageName, string xmlDataName)
{
string path = "/data/data/" + packageName + "/shared_prefs/" + xmlDataName + ".xml";
FileStream levelFile = File.Open(path, FileMode.Open);
XmlDocument xmlDoc = new XmlDocument();
string xmlText = "";
using (StreamReader sr = new StreamReader(levelFile))
{
string line = null;
do
{
line = sr.ReadLine();
xmlText = xmlText + line + "\n";
} while (line != null);
sr.Close();
levelFile.Close();
}
xmlDoc.LoadXml(xmlText);
var baseNode = xmlDoc.DocumentElement;
foreach (XmlNode node in baseNode.ChildNodes)
{
Debug.Log("Type: " + node.Name);
if (node.Attributes["name"] != null)
Debug.Log("name: " + node.Attributes["name"].Value);
else
Debug.Log("Empty");
if (node.Attributes["value"] != null)
Debug.Log("Value: " + node.Attributes["value"].Value);
else
Debug.Log("Empty");
}
}
Usage:
packageName = "com.yourcompany.yourgame"
xmlDataName = getSharedPreferences file name (in my question, it's "kayit")
You can see all 'int' and 'bool' data on Android Device Monitor.
I need to implement a service in android that must be able to monitor a folder to detect a certain file and read what it contains. I'm having a strange behavior with my code and I can't find the reason. This is my relevant code.
public void onCreate(){
lectorFichCSV = new LectorFichCSV(); //object to read CSV files
ftpFileObserver = new FileObserver(filePath.getAbsolutePath()){
public void onEvent(int event, String file) {
if((FileObserver.CREATE & event) != 0){
Log.i("INFO: ", filePath.getAbsolutePath() + "/" + file + " is created");
if(file.substring(0,3).equals("RVE")){ //If file is created and the one I expect
try{
Log.i("INFO: ", "We have a RVE answer");
is = new FileInputStream(filePath + "/" + file);
lineaVent = lectorFichCSV.parseCSVFileAsList(is); //Get information in a list
//Get dao from ORMLite
dao = getHelper().getLineaVentDao();
Iterator<String[]> iterator = lineaVent.iterator();
if(iterator.hasNext()){
String[] aux = iterator.next();
Log.i("INFO:", "CodLineaVent "+aux[0]);
if(aux[2].equals("S")){
//Update DB information accordin to my file
UpdateBuilder<LineaVent, Integer> updateBuilder = dao.updateBuilder();
updateBuilder.where().eq("_id", aux[0]);
updateBuilder.updateColumnValue("valido", true);
updateBuilder.updateColumnValue("saldo", true);
updateBuilder.update();
lineaVent.clear();
}else if(aux[2].equals("N")){
UpdateBuilder<LineaVent, Integer> updateBuilder = dao.updateBuilder();
updateBuilder.where().eq("_id", aux[0]);
updateBuilder.updateColumnValue("saldo", false);
updateBuilder.update();
lineaVent.clear();
}
File fileToDel = new File(filePath + "/" + file);
fileToDel.delete();
}
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(SQLException e){
e.printStackTrace();
}
}
I debugged the code and sometimes is working and sometimes I get lineaVent.size() == 0. I'm going crazy with this, I'm thinking, is it possible that events occurs faster than the creation of my file? that would be the reason when I tried to parse my CSV file into my List object is size = 0? In that case I'm not getting any FileNotFoundException.
Any help will be appreciate. Thank you.
I am not an expert with the inotify POSIX API that, IIRC, underlies FileObserver. However, given that there are separate events for CREATE, MODIFY, and CLOSE_WRITE, it stands to reason that the CREATE event is solely for file creation -- in other words, allocating a new entry in the filesystem for the file. That would either create an empty file, or perhaps a file with some initial load of bytes, but where other MODIFY calls might be needed to write out the full contents. CLOSE_WRITE would then be called to indicate that whoever was writing to the file has now closed their file handle.
Hence, if you are watching for some file to be created, to read it in, watch for CREATE, then watch for CLOSE_WRITE on that same file, and then try to read it, and see if that works better.
I want to upload image on Google Cloud Storage from my android app. For that I searched and found that GCS JSON Api provides this feature. I did a lot of research for Android sample which demonstrates its use. On the developer site they have provided code example that only support java. I don't know how to use that API in Android. I referred this and this links but couldn't get much idea. Please guide me on how i can use this api with android app.
Ok guys so I solved it and got my images being uploaded in Cloud Storage all good.
This is how:
Note: I used the XML API it is pretty much the same.
First, you will need to download a lot of libraries.
The easiest way to do this is create a maven project and let it download all the dependencies required. From this sample project :
Sample Project
The libraries should be:
Second, you must be familiar with Cloud Storage using the api console
You must create a project, create a bucket, give the bucket permissions, etc.
You can find more details about that here
Third, once you have all those things ready it is time to start coding.
Lets say we want to upload an image:
Cloud storage works with OAuth, that means you must be an authenticated user to use the API. For that the best way is to authorize using Service Accounts. Dont worry about it, the only thing you need to do is in the API console get a service account like this:
We will use this service account on our code.
Fourth, lets write some code, lets say upload an image to cloud storage.
For this code to work you must put your key generated in step 3 in assets folder, i named it "key.p12".
I don't recommend you to do this on your production version, since you will be giving out your key.
try{
httpTransport= new com.google.api.client.http.javanet.NetHttpTransport();
//agarro la key y la convierto en un file
AssetManager am = context.getAssets();
InputStream inputStream = am.open("key.p12"); //you should not put the key in assets in prod version.
//convert key into class File. from inputstream to file. in an aux class.
File file = UserProfileImageUploadHelper.createFileFromInputStream(inputStream,context);
//Google Credentianls
GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(Collections.singleton(STORAGE_SCOPE))
.setServiceAccountPrivateKeyFromP12File(file)
.build();
String URI = "https://storage.googleapis.com/" + BUCKET_NAME+"/"+imagename+".jpg";
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);
GenericUrl url = new GenericUrl(URI);
//byte array holds the data, in this case the image i want to upload in bytes.
HttpContent contentsend = new ByteArrayContent("image/jpeg", byteArray );
HttpRequest putRequest = requestFactory.buildPutRequest(url, contentsend);
com.google.api.client.http.HttpResponse response = putRequest.execute();
String content = response.parseAsString();
Log.d("debug", "response is:"+response.getStatusCode());
Log.d("debug", "response content is:"+content);} catch (Exception e) Log.d("debug", "Error in user profile image uploading", e);}
This will upload the image to your cloud bucket.
For more info on the api check this link Cloud XML API
Firstly, You should get the below information by registering your application in the GCP console.
private final String pkcsFile = "xxx.json";//private key file
private final String bucketName = "your_gcp_bucket_name";
private final String projectId = "your_gcp_project_id";
Once you get the credentials, you should put the private key (.p12 or .json) in your assets folder. I'm using JSON format private key file. Also, you should update the image location to upload.
#RequiresApi(api = Build.VERSION_CODES.O)
public void uploadImageFile(String srcFileName, String newName) {
Storage storage = getStorage();
File file = new File(srcFileName);//Your image loaction
byte[] fileContent;
try {
fileContent = Files.readAllBytes(file.toPath());
} catch (IOException e) {
e.printStackTrace();
return;
}
if (fileContent == null || fileContent.length == 0)
return;
BlobInfo.Builder newBuilder = Blob.newBuilder(BucketInfo.of(bucketName), newName);
BlobInfo blobInfo = newBuilder.setContentType("image/png").build();
Blob blob = storage.create(blobInfo, fileContent);
String bucket = blob.getBucket();
String contentType = blob.getContentType();
Log.e("TAG", "Upload File: " + contentType);
Log.e("File ", srcFileName + " uploaded to bucket " + bucket + " as " + newName);
}
private Storage getStorage() {
InputStream credentialsStream;
Credentials credentials;
try {
credentialsStream = mContext.getAssets().open(pkcsFile);
credentials = GoogleCredentials.fromStream(credentialsStream);
} catch (IOException e) {
e.printStackTrace();
return null;
}
return StorageOptions.newBuilder()
.setProjectId(projectId).setCredentials(credentials)
.build().getService();
}
I have the following problem:
I develop a .zip file download with .pdf selected inside a function on c#.
The function creates the .zip file on a temp folder on the server and the HTTP Response return this file.
This function works great when is called from windows, and IOS. But when I call this function on Android it never downloads the file.
On the server I see that the function create the .zip file again and again when it's called from android browser (chrome, dolphin...) and it's never returned.
The strange thing is that I could run it well when I selected 90 .pdf files (although the function is called twice for no reason), but when I select 140 (or more) the issue happens again.
Here is the code:
**string dirName = Utiles.GetNewName();
zipName += ".ZIP\"";
string urlRet = _mSTempPath + #"\" + dirName + ".ZIP";
string urlDelete = _mSTempPath + #"\" + dirName;
System.IO.Stream iStream = null;
// Total bytes to read:
long dataToRead;
//HttpResponse resp = _page.Response;
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ClearHeaders();
using (ZipFile zip = new ZipFile())
{
foreach (string url in filesURLs)
{
zip.AddFile(url,"");
}
zip.Save(_mSTempPath + #"\" + dirName + ".ZIP");
}
// Open the file.
iStream = new System.IO.FileStream(urlRet, System.IO.FileMode.Open,
System.IO.FileAccess.Read, System.IO.FileShare.Read);
// Total bytes to read:
dataToRead = iStream.Length;
HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename=\"" + zipName);
HttpContext.Current.Response.ContentType = "application/octet-stream";
HttpContext.Current.Response.AddHeader("content-length", dataToRead.ToString());
HttpContext.Current.Response.BufferOutput = true;
HttpContext.Current.Response.TransmitFile(urlRet);
HttpContext.Current.Response.Flush();**
Please, I will be very grateful if anyone can help.
Thanks again!
I am using Eclipse for Android SDK on Linux, and searching for a way to add the date and starttime of the compilation to one of the xml files. I like to see on the device which build version I am using, without updating this information before every compile step manually.
So far by searching the net I only found hints like "use ant".
I guess I have to use /proc/driver/rtc which is a dynamic "file" provided by the linux kernel that contains real time updated lines with colon separated text named for example "rtc_date" and "rtc_time". Including it and use the app on the device to get the information extracted.
Is there a better way? Like having eclipse either by knowing the time or stripping the information from proc and putting it at compile time in the xml file?
Its my first time using eclipse, so please excuse if I asked something obvious or impossible.
Regards
ct
I am using this code to get application build time. I know this is not outputting to an XML, but if you are trying to get when the app was build, this should work.
private long getAppBuildTime() {
if(cachedAppBuildTime == null) {
try{
ApplicationInfo ai = appContext.getPackageManager().getApplicationInfo(appContext.getPackageName(), 0);
ZipFile zf = new ZipFile(ai.sourceDir);
ZipEntry ze = zf.getEntry("classes.dex");
cachedAppBuildTime = ze.getTime();
log("app build time " + cachedAppBuildTime);
}catch(Throwable t){
return 1;
}
}
return cachedAppBuildTime;
}
The appContext variable in the code is obtained via context.getApplicationContext()
I use the same strategy as yigit except I prefer the MANIFEST.MF file.
This one is regenerated even if a layout is modified (which is not the case for classes.dex).
It result in the following code:
private long mAppBuildTime = -1;
public long getAppBuildTime() {
if (mAppBuildTime == -1) {
try{
ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), 0);
ZipFile zf = new ZipFile(ai.sourceDir);
ZipEntry ze = zf.getEntry("META-INF/MANIFEST.MF");
mAppBuildTime = ze.getTime();
zf.close();
}catch(Exception e){
}
}
return mAppBuildTime;
}