I am trying to check an xml against an schema for Android, but in the first very line of the function, when creating the schema factory instance, I get an exception.
Exception line:
schemaFactory= SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
I have also used XMLSchema-instance and XMLSchema, but got the same exception at the beginning.
I have seen that many other people are having the same issue, like this, but I haven't found the answer to this problem yet.
FYI - I am using it in the following function:
public static boolean validateWithExtXSDUsingSAX(String xml, String xsd) throws
ParserConfigurationException, IOException {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(false);
factory.setNamespaceAware(true);
SchemaFactory schemaFactory = null;
try {
schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
} catch (Exception e) {
System.out.println("schema factory error" + e.getMessage());
}
SAXParser parser = null;
try {
factory.setSchema(schemaFactory.newSchema(new Source[] { new StreamSource(xsd) }));
parser = factory.newSAXParser();
} catch (SAXException se) {
System.out.println("SCHEMA : " + se.getMessage()); // problem in
// the XSD
// itself
return false;
}
XMLReader reader = parser.getXMLReader();
reader.setErrorHandler(
new ErrorHandler() {
public void warning(SAXParseException e) throws SAXException {
System.out.println("WARNING: " + e.getMessage()); // do
// nothing
}
public void error(SAXParseException e) throws SAXException {
System.out.println("ERROR : " + e.getMessage());
throw e;
}
public void fatalError(SAXParseException e) throws SAXException {
System.out.println("FATAL : " + e.getMessage());
throw e;
}
});
reader.parse(new InputSource(xml));
return true;
} catch (ParserConfigurationException pce) {
throw pce;
} catch (IOException io) {
throw io;
} catch (SAXException se) {
return false;
}
}
EDIT:
There are some issues with the Java XML validator included in the original versions of Android. You can try to use Xerces instead, you can download it form here:
http://code.google.com/p/xerces-for-android/
Although there are no downloads in the downloads section, you can do an SVN checkout to download the source code.
I had the same issue and found lots of similar questions out there, but no good examples on how to do it. The following is what I did with Xerces-for-Android to get my stuff to work. Good luck :)
The following worked for me:
Create a validation utility.
Get both the xml and xsd into file on the android OS and use the validation utility against it.
Use Xerces-For-Android to do the validation.
Android does support some packages which we can use, I created my xml validation utility based on: http://docs.oracle.com/javase/1.5.0/docs/api/javax/xml/validation/package-summary.html
My initial sandbox testing was pretty smooth with java, then I tried to port it over to Dalvik and found that my code did not work. Some things just aren't supported the same with Dalvik, so I made some modifications.
I found a reference to xerces for android, so I modified my sandbox test of (the following doesn't work with android, the example after this does):
import java.io.File;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.w3c.dom.Document;
/**
* A Utility to help with xml communication validation.
*/
public class XmlUtil {
/**
* Validation method.
* Base code/example from: http://docs.oracle.com/javase/1.5.0/docs/api/javax/xml/validation/package-summary.html
*
* #param xmlFilePath The xml file we are trying to validate.
* #param xmlSchemaFilePath The schema file we are using for the validation. This method assumes the schema file is valid.
* #return True if valid, false if not valid or bad parse.
*/
public static boolean validate(String xmlFilePath, String xmlSchemaFilePath) {
// parse an XML document into a DOM tree
DocumentBuilder parser = null;
Document document;
// Try the validation, we assume that if there are any issues with the validation
// process that the input is invalid.
try {
// validate the DOM tree
parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
document = parser.parse(new File(xmlFilePath));
// create a SchemaFactory capable of understanding WXS schemas
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
// load a WXS schema, represented by a Schema instance
Source schemaFile = new StreamSource(new File(xmlSchemaFilePath));
Schema schema = factory.newSchema(schemaFile);
// create a Validator instance, which can be used to validate an instance document
Validator validator = schema.newValidator();
validator.validate(new DOMSource(document));
} catch (Exception e) {
// Catches: SAXException, ParserConfigurationException, and IOException.
return false;
}
return true;
}
}
The above code had to be modified some to work with xerces for android (http://gc.codehum.com/p/xerces-for-android/). You need SVN to get the project, the following are some crib notes:
download xerces-for-android
download silk svn (for windows users) from http://www.sliksvn.com/en/download
install silk svn (I did complete install)
Once the install is complete, you should have svn in your system path.
Test by typing "svn" from the command line.
I went to my desktop then downloaded the xerces project by:
svn checkout http://xerces-for-android.googlecode.com/svn/trunk/ xerces-for-android-read-only
You should then have a new folder on your desktop called xerces-for-android-read-only
With the above jar (Eventually I'll make it into a jar, just copied it directly into my source for quick testing. If you wish to do the same, you can making the jar quickly with Ant (http://ant.apache.org/manual/using.html)), I was able to get the following to work for my xml validation:
import java.io.File;
import java.io.IOException;
import mf.javax.xml.transform.Source;
import mf.javax.xml.transform.stream.StreamSource;
import mf.javax.xml.validation.Schema;
import mf.javax.xml.validation.SchemaFactory;
import mf.javax.xml.validation.Validator;
import mf.org.apache.xerces.jaxp.validation.XMLSchemaFactory;
import org.xml.sax.SAXException;
/**
* A Utility to help with xml communication validation.
*/public class XmlUtil {
/**
* Validation method.
*
* #param xmlFilePath The xml file we are trying to validate.
* #param xmlSchemaFilePath The schema file we are using for the validation. This method assumes the schema file is valid.
* #return True if valid, false if not valid or bad parse or exception/error during parse.
*/
public static boolean validate(String xmlFilePath, String xmlSchemaFilePath) {
// Try the validation, we assume that if there are any issues with the validation
// process that the input is invalid.
try {
SchemaFactory factory = new XMLSchemaFactory();
Source schemaFile = new StreamSource(new File(xmlSchemaFilePath));
Source xmlSource = new StreamSource(new File(xmlFilePath));
Schema schema = factory.newSchema(schemaFile);
Validator validator = schema.newValidator();
validator.validate(xmlSource);
} catch (SAXException e) {
return false;
} catch (IOException e) {
return false;
} catch (Exception e) {
// Catches everything beyond: SAXException, and IOException.
e.printStackTrace();
return false;
} catch (Error e) {
// Needed this for debugging when I was having issues with my 1st set of code.
e.printStackTrace();
return false;
}
return true;
}
}
Some Side Notes:
For creating the files, I made a simple file utility to write string to files:
public static void createFileFromString(String fileText, String fileName) {
try {
File file = new File(fileName);
BufferedWriter output = new BufferedWriter(new FileWriter(file));
output.write(fileText);
output.close();
} catch ( IOException e ) {
e.printStackTrace();
}
}
I also needed to write to an area that I had access to, so I made use of:
String path = this.getActivity().getPackageManager().getPackageInfo(getPackageName(), 0).applicationInfo.dataDir;
A little hackish, it works. I'm sure there is a more succinct way of doing this, however I figured I'd share my success, as there weren't any good examples that I found.
Link for download jar file xerces-for-android.jar from google repository.
If above link is unavailable, use this page for downloading: xerces
Related
I have an odd problem; if I run this code I get a java.io.FileNotFoundException: https://graph.facebook.com/debug_token?input_token=1234&access_token=1234. This only occurs when I call client.getInputStream() inside my AsyncTask. Click the link: it clearly works.
Let's call this case 1.
Now, when I run the exact same code outside of my AsyncTask, I get a NetworkOnMainThreadException, but client.getInputStream() works...
Consider this case 2.
I know why I get the NetworkOnMainThreadException in case 2, but I don't understand why the FileNotFoundException only happens in case 1, and not in case 2. The code is identical! I've been looking at this for hours and I just don't know what I am doing wrong.
EDIT: apperently the FileNotFoundException occurs because of an error response code. I figured this out by getting the error stream with .getErrorStream() when the exception occurs.
import android.os.AsyncTask;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Scanner;
import javax.net.ssl.HttpsURLConnection;
public class Temp {
private String getResponse(InputStream stream){
Scanner s = new Scanner(stream).useDelimiter("\\A");
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
return s.hasNext() ? s.next() : "";
}
public void run(String url){
URL uri;
HttpsURLConnection client = null;
try {
uri = new URL(url);
client = (HttpsURLConnection) uri.openConnection();
client.setReadTimeout(15*1000);
} catch (IOException e) {
e.printStackTrace();
}
new RetrieveStream().execute(client);
}
private class RetrieveStream extends AsyncTask<HttpsURLConnection, Void, String> {
private String returnString = null; //don't change this!
HttpsURLConnection client;
#Override
protected String doInBackground(HttpsURLConnection... client) {
try {
this.client = client[0];
InputStream stream = this.client.getInputStream();
Log.d(getClass().getSimpleName(), "response: "+getResponse(this.client.getInputStream()));
} catch (FileNotFoundException e) {
Log.d(getClass().getSimpleName(), "error output: "+getResponse(this.client.getErrorStream()));
e.printStackTrace();
} catch (IOException e) {
Log.d(getClass().getSimpleName(), "error: "+getResponse(this.client.getErrorStream()));
e.printStackTrace();
}
this.client.disconnect();
return returnString;
}
protected void onPostExecute(String output) {
Log.d(getClass().getSimpleName(), "output: "+output);
}
}
}
i am not deep into android development, but since the Thread seem to be aware of connections (implied by "NetworkOnMainThreadException"), i'd suggest to handover the URL instance to your AsyncTask and open the connection there, instead of hand over the client.
Apart from this, by reading the api, i'd expect a
client.connect();
before
client.getInputStream();
get's called.
References:
https://developer.android.com/reference/java/net/URL.html#openConnection()
https://developer.android.com/reference/java/net/URLConnection.html#getInputStream()
It's not very clear why the FileNotFoundException occurs, but I was able to get the response with .getErrorStream() instead of .getInputStream(). My question is edited accordingly. Please ignore the other answers, they provide no solutions.
I am writing because I created a computer base application that simple store data in a sqlite database, I used java through eclipse, the problem is that the application works fine on the pc that it was built on as a jar file, but when I distribute the application to my people I get this message on their computer
java.sql.SQLException path to c:user//usuario/documents/school.sqlite does not exist
The question is . How to change the code tomake the application also work in other computers as well and not only on the pc that it was built on?
here is the code I used
import java.sql.*;
import javax.swing.*;
public class sqlConnection {
Connection conn=null;
public static Connection dbConnector()
{
try{
Class.forName("org.sqlite.JDBC");
Connection conn=DriverManager.getConnection("jdbc:sqlite:C:\\Users\\USUARIO\\Documents\\workspace\\School2015.sqlite");
JOptionPane.showMessageDialog(null, "BIENVENIDO! Estás Conectado");
return conn;
}catch (Exception e)
{
JOptionPane.showMessageDialog(null, e);
return null;
}
}
}
Do not use 'C:\Users\USUARIO\Documents\workspace\School2015.sqlite'
Use relative path instead like ..\..\..\workspace\
or if you need to set up path on runtime use it as String which should be given as input parameter to your program
You can use this code.
import java.sql.*;
import javax.swing.*;
public class sqlConnection {
Connection conn=null;
public static Connection dbConnector()
{
try{
Class.forName("org.sqlite.JDBC");
Connection conn=DriverManager.getConnection("jdbc:sqlite:C:\\Users\\USUARIO\\Documents\\workspace\\School2015.sqlite");
JOptionPane.showMessageDialog(null, "BIENVENIDO! Estás Conectado");
return conn;
}catch (Exception e)
{
JOptionPane.showMessageDialog(null, e);
return null;
}}}
I'm trying to build a plugin-System, where DexClassLoader is fetching code from other installed apks containing fragments(my plugins), and showing them in my host. This is working quite nice.
I also like to make the plugins hotswappable, this means I can change the code from a plugin, install it new and the host will notice and will load the new code. This also works, if I'm changing the code for the first time. (Although I thought it shouldn't, it seems I've got a wrong understanding of this code:
try {
requiredClass = Class.forName(fullName);
} catch(ClassNotFoundException e) {
isLoaded = false;
}
)
If i'm trying it a second time with the same plugin, the host shuts down at requiredClass = classLoader.loadClass(fullName); with something like
libc Fatal signal 7 (SIGBUS) at 0x596ed4d6 (code=2), thread 28814
(ctivityapp.host)
Does anybody has a deeper insight in the functionality of DexClassLoader and may tell me, what is happening here? I'm quite stuck at this.
Heres the full code of the method loading the foreign code:
/**
* takes the name of a package as String, and tries to load the code from the corresponding akp using DexclassLaoder.
* Checking if a package is a valid plugin must be done before calling this.
* The Plugin must contain a public class UI that extends Fragment and implements plugin as a starting point for loading
* #param packageName The full name of the package, as String
* #return the plugins object if loaded, null otherwise
*/
private Plugin attachPluginToHost(String packageName) {
try {
Class<?> requiredClass = null;
final ApplicationInfo info = context.getPackageManager().getApplicationInfo(packageName,0);
final String apkPath = info.sourceDir;
final File dexTemp = context.getDir("temp_folder", 0);
final String fullName = packageName + ".UI";
boolean isLoaded = true;
// Check if class loaded
try {
requiredClass = Class.forName(fullName);
} catch(ClassNotFoundException e) {
isLoaded = false;
}
if (!isLoaded) {
final DexClassLoader classLoader = new DexClassLoader(apkPath, dexTemp.getAbsolutePath(), null, context.getApplicationContext().getClassLoader());
requiredClass = classLoader.loadClass(fullName);
}
if (null != requiredClass) {
// Try to cast to required interface to ensure that it's can be cast
final Plugin plugin = Plugin.class.cast(requiredClass.newInstance());
installedPlugins.put(plugin.getName(), plugin);
return plugin;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
Many thanks in advance!
Not that it really matters (As nobody is actually viewing this), or that I even understand what's going on, but deleting the corresponding file of the plugin in dexTemp.getAbsolutePath() before reloading it solves the problem.
PS: Tumbleweed-Badge, YAY!
I have an android application which has to load dynamically class ,an undefined number of a jar class which implemented an interface.
In fact, I look at a directory and list all the jar files which are in this directory
I open the manifest of the jar file and find the associated class and list them.
And after, i instancied a dexClassLoader to load all the jar files and to find if the classes i have found in the manisfest implement my interface.
Like this I can have all the class which implemented my interface without knowing them at the begginning
To resume, i have a list of class jar which implement my interface but the list is unknown by my android application and by me. The list of jar class can changed each time i launch my application.
But when i tried to create the DexClassLoader it is failed. I have always a null pointer
DexClassLoader classLoader = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),dexOutputDir.getAbsolutePath(), null, ClassLoader.getSystemClassLoader());
To make my test i used the emulator. I have copied with my DDMS the jar files into the directory
/data/data/com.example.Myappli/JarFilesDirectory/*.jar
Notice that my jar file contents the dex file
I read a lot of thing about this. Some permissions issues
I have tried every thing but not found the solution
Can someone help me please !!!
here the content of a manifest of a jar file
Manifest-Version: 1.0
Module-Class: com.example.asktester.AskPeripheral
Here my code :
public class ModuleLoader {
private static List<URL> urls = new ArrayList<URL>();
private static List<String> getModuleClasses(String folder)
{
List<String> classes = new ArrayList<String>();
//we are listing the jar files
File[] files = new File(folder).listFiles(new ModuleFilter());
for(File f : files)
{
JarFile jarFile = null;
try
{
//we open the jar file
jarFile = new JarFile(f);
//we recover the manifest
Manifest manifest = jarFile.getManifest();
//we recover the class
String moduleClassName = manifest.getMainAttributes().getValue("Module-Class");
classes.add(moduleClassName);
urls.add(f.toURI().toURL());
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if(jarFile != null)
{
try
{
jarFile.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
return classes;
}
private static class ModuleFilter implements FileFilter {
#Override
public boolean accept(File file) {
return file.isFile() && file.getName().toLowerCase().endsWith(".jar");
}
}
private static ClassLoader classLoader;
public static List<IPeripheral> loadModules(String folder, Context CurrentContext) throws IOException, ClassNotFoundException
{
List<IPeripheral> modules = new ArrayList<IPeripheral>();
List<String> classes = getModuleClasses(folder);
final File dexInternalStoragePath = new File(CurrentContext.getDir("dex", Context.MODE_PRIVATE),"ask.dex");
File dexOutputDir = CurrentContext.getDir("dex", Context.MODE_PRIVATE);
final File dexClasses = new File(CurrentContext.getDir("dex", Context.MODE_PRIVATE),"ASK.jar");
DexFile dexFile = DexFile.loadDex(dexClasses.getAbsolutePath(), dexOutputDir.getAbsolutePath(), 0);
DexClassLoader classLoader = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),dexOutputDir.getAbsolutePath(), null, ClassLoader.getSystemClassLoader());
//Class<?> myClass = classLoader.loadClass("com.example.asktester.AskPeripheral");
if(IPeripheral.class.isAssignableFrom(myClass )){
Class<IPeripheral> castedClass = (Class<IPeripheral>)myClass ;
IPeripheral module = castedClass.newInstance();
modules.add(module);
}
}
catch (ClassNotFoundException e1)
{
e1.printStackTrace();
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
}
return modules;
}
I found the solution to my issue.
To load dynamically jar, classes which implement an interface in an android application, some jobs need to be done in the jar :
Create your own manisfest for the jar and put this information
Manifest-Version: 1.0
Module-Class: com.example.myjar.MyPeripheral
Export your jar using eclipse and put in parameter that it uses its own manisfest
Create the classes.dex associated to the jar
(this file is needed by the Dalvik VM, simply jar can not be read by the dalvik VM)
dx --dex --output=C:\classes.dex C:\MyJar.jar
Be carefull, the name of the dex file MUST BE classes.dex
Add the file classes.dex in the jar file
aapt add C:\MyJar.jar C:\classes.dex
You need also to have the right to write into the dalvik cache directory
adb shell chmod 777 /data/dalvik-cache
Do it each time, your relaunch your emulator
put this jar file into the emulator for example on the SDcard
Use a PathClassLoader to load the jar file
dalvik.system.PathClassLoader myClassLoader = new dalvik.system.PathClassLoader("/Sdcard/MyJar.jar", ModuleLoader.class.getClassLoader());
NB : the LogCat in Eclipse gives you precious information. Do not forget to look at its messages
Below, the code :
My interface :
package com.example.StandartPeripheral;
public interface IPeripheral {
public boolean Initialize();
public boolean configure();
public boolean execute();
public String GetName();
}
MyPeripheral which implements the interface
public class MyPeripheral implements IPeripheral {
//public static void main(String[] args) {}
private final String PeripheralName = "MyPeripheral";
public boolean Initialize()
{
System.out.println("Initialize ");
return true;
};
public boolean configure()
{
System.out.println("Configure !");
return true;
};
public boolean execute()
{
System.out.println("Execute !");
return true;
};
public String GetName()
{
return PeripheralName;
}
}
How to load dynamically the jar files
package com.example.ModuleLoader;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import com.example.StandartPeripheral.IPeripheral;
public class ModuleLoader {
private static List<URL> urls = new ArrayList<URL>();
// to retrieve the unknown list of jar files contained in the directory folder
// in my case it was in the SDCard folder
// link to create a SDCard directory on the Eclipse emulator
// http://blog.lecacheur.com/2010/01/14/android-avoir-acces-a-une-carte-memoire-dans-lemulateur/
// retrieve the classes of all this jar files and their URL (location)
private static List<String> getModuleClasses(String folder)
{
List<String> classes = new ArrayList<String>();
//we are listing the jar files
File[] files = new File(folder).listFiles(new ModuleFilter());
for(File f : files)
{
JarFile jarFile = null;
try
{
//we open the jar file
jarFile = new JarFile(f);
//we recover the manifest
Manifest manifest = jarFile.getManifest();
//we recover the class name of our peripherals thanks to ours manifest
String moduleClassName = manifest.getMainAttributes().getValue("Module-Class");
classes.add(moduleClassName);
urls.add(f.toURI().toURL());
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if(jarFile != null)
{
try
{
jarFile.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
return classes;
}
private static class ModuleFilter implements FileFilter {
#Override
public boolean accept(File file) {
return file.isFile() && file.getName().toLowerCase().endsWith(".jar");
}
}
//This function loads the jar file into the dalvik system
// retrieves the associated classes using its name
// and try to know if the loaded classes are implementing our interface
public static List<IPeripheral> loadModules(String folder, Context CurrentContext) {
List<IPeripheral> modules = new ArrayList<IPeripheral>();
List<String> classes = getModuleClasses(folder);
int index = 0;
for(String c : classes)
{
try
{
dalvik.system.PathClassLoader myClassLoader = new dalvik.system.PathClassLoader(urls.get(index).toString(), ModuleLoader.class.getClassLoader());
Class<?> moduleClass = Class.forName(c, true, myClassLoader);
//check and cast to an interface, then use it
if(IPeripheral.class.isAssignableFrom(moduleClass))
{
#SuppressWarnings("unused")
Class<IPeripheral> castedClass = (Class<IPeripheral>)moduleClass;
IPeripheral module = (IPeripheral)moduleClass.newInstance();
modules.add(module);
}
index++;
}
catch (ClassNotFoundException e1)
{
e1.printStackTrace();
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
}
return modules;
}
}
It would also be a good idea to use the ClassLoader rather than the Dalvik path class loader:
ClassLoader cl = new DexClassLoader(url, ApplicationConstants.ref_currentActivity.getFilesDir().getAbsolutePath(), null, ModuleList.class.getClassLoader());
Where url is the location of the file you are loading "from".
ApplicationConstants.ref_currentActivity is simply an activity class - my implementation is fairly complicated due to dynamic modular loading - so I needed to keep track of it this way - but others can probably just use "this" if that class is already an activity.
The MAIN reason for using the class loader over the dalvik one - is that it doesn't require files to be written to cache, and therefore the permission chmod 777 /data/dalvik-cache is unrequired - and of course you also wouldn't need to pass this command from root on a rooted phone pro-grammatically either.
It's always best to not have users forced to root their phones, simply because your app requires it. Especially if your app is a more professional "meant-for-company-use-type" -.Work Policies against the use of rooted phones are usually in place too.
If anyone has any questions on modular loading - please feel free to ask.
The base of my current code is all thanks to Virginie Voirin, along with my own modifications. Good luck all!
I am an amateur in android coding.
I am trying to setup an android app with the ability to download a file from an ftp server. While running the code on the android 2.2 emulator, i am able to connect to the ftp server but the downloading part is showing an error. LogCat gives "download failed".
package com.ftconnect.down;
import java.io.FileOutputStream;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import org.apache.commons.net.ftp.*;
public class FTPConnectActivity extends Activity {
/** Called when the activity is first created. */
public FTPClient mFTPClient = null;
public boolean mConnect;
public boolean mDownload;
public boolean mDisconnected;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mConnect = ftpConnect("xxx.xxx.xxx.xxx", "admin",
"123456", 21);
mDownload = ftpDownload("xxx.xxx.xxx.xxx/ftp.mp3", "/sdcard");
mDisconnected = ftpDisconnect();
}
public boolean ftpConnect(String host, String username, String password,
int port) {
try {
mFTPClient = new FTPClient();
// connecting to the host
mFTPClient.connect(host, port);
Log.d("ftpConnectApp", "Connecting to " + host);
// now check the reply code, if positive mean connection success
if (FTPReply.isPositiveCompletion(mFTPClient.getReplyCode())) {
// login using username & password
boolean status = mFTPClient.login(username, password);
return status;
}
} catch (Exception e) {
Log.d("ftpConnectApp", "Error: could not connect to host " + host);
}
return false;
}
public boolean ftpDownload(String srcFilePath, String desFilePath) {
boolean status = false;
try {
FileOutputStream desFileStream = new FileOutputStream(desFilePath);
;
status = mFTPClient.retrieveFile(srcFilePath, desFileStream);
desFileStream.close();
return status;
} catch (Exception e) {
Log.d("ftpConnectApp", "download failed");
}
return status;
}
public boolean ftpDisconnect() {
try {
mFTPClient.logout();
mFTPClient.disconnect();
return true;
} catch (Exception e) {
Log.d("ftpConnectApp",
"Error occurred while disconnecting from ftp server.");
}
return false;
}
}
I have setup the internet and write external permission in the android manifest file. Should i include any other permissions?
Also, let me know if there is any changes to be made to the code above. Is the destination address as '/sdcard' correct?
Thanks in advance.
You need to add Exception variable in your log message. You may also want to print full stack trace of the problem using:
e.printStackTrace();
Generally /sdcard should work, however it is more reliable to request SD card location using Environment object. See more details about file storage on android in
link
Also, let me know if there is any changes to be made to the code above. Is the destination address as '/sdcard' correct?
At the very least you should use /sdcard/filename.ext although this would only be OK for testing purposes if you are sure that /sdcard is a valid root directory.
To do things correctly, use getExternalFilesDir to find the correct path to the external storage 'files' directory that can be used for 'private' files for your own app. See the example code in that link for how to use it. You'll need to provide a filename for the output stream not just a path to a directory.
This may not be the answer to your problem but simply using...
FileOutputStream desFileStream = new FileOutputStream(desFilePath);
...when desFilePath is a directory, i.e., /sdcard, and not a file is guaranteed to fail.
Use
mFTPClient.enterLocalActiveMode();
after login