不用appstore照样发布应用,无限应用下载实战


首先声明一下小弟对ios也不是很熟,不喜勿喷啊。


首先说一下需求吧,现在有很多的应用已经是存储在数据库中,而ios的设备只需打开指定的网址点击相应应用链接即可完成应用的下载。


好,现在开始走流程具体实现的过程。


一、连接到sybase数据库(应用的数据是存储在这个数据库中的),连接需要的jdbc自己上网上找(jconn3.jar)。

package com.justsy.db;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBManager {
	// 返回数据库连接对象
	public Connection createConn() {
		Connection conn = null;
		try {
			Class.forName("com.sybase.jdbc3.jdbc.SybDriver");
			String url = "jdbc:sybase:Tds:192.168.2.143:2638/AfariaDb_Asa11";
			conn = DriverManager.getConnection(url, "akwolf", "123456");
			return conn;

		} catch (Exception fe) {
			System.err.println("createConn(): " + fe.getMessage());
			return null;
		}

	}
}


二、一个设备要得到可用的应用列表是传递当前设备id到数据库中取得的,


 

    
        
        AppList
        
        
    
    
    	
    


template.plist





   items
   
       
           assets
           
               
                   kind
                   software-package
                   url
                   http://192.168.2.27:8080/justsy/CSuiteBuyer_Int1.ipa
               
               
                   kind
                   display-image
                   needs-shine
                   
                   url
                   http://192.168.2.27:8080/justsy/ifw114.png
               
	       
                   kind
                   full-size-image
                   needs-shine
                   
                   url
                   http://192.168.2.27:8080/justsy/ifw114.png
               
           metadata
           
               bundle-identifier
               com.sap.DS4M.C-SuiteBuyer.internal
               bundle-version
               8.0.3.99
               kind
               software
               subtitle
               Everlight
               title
               Everlight
           
       
   




好对上面那段代码我要解释一下:

1、取得设备id使用ajax请求回可用的应用列表,并拼装成超链接列表。

2、在拼装超链接列表时是有讲究的,http://192.168.2.101:8080/JustsyApp/template.plist">Install App

红色部分是一个应用的描述文件,而描述文件中指明了应用下载的地址,和显示图片的地址及一些描述信息

注意点:在做到这一步时遇到一个的问题,在url超链接中无法接参数加上"=","{}"或"&"之类的字符点击就没反应,最后的解决方案是使用":"进行参数的分割。不知道这其中有什么门道,知道的大虾可以指点哈。


三、好了现在的任务重点是根据点击的超链接动态的生成plist的描述xml文件,这里使用jdom(jar包自己上网上找)进行xml的相关操作,恩,,把根据应用id生成plist描述文件的代码贴出来

package com.justsy.productXML.jdom;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.xml.sax.SAXException;

import com.justsy.db.DBManager;

public class RroductFile extends HttpServlet {
	private static final long serialVersionUID = 1L;


	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		try {
			String param = "" ;
			
			// 格式[PackageID:2a67a513-bbd5-431d-8630-f03b39b89ea1]
			Enumeration en = request.getParameterNames() ;
			if(en.hasMoreElements()){
				param = en.nextElement() ;
			}
			// 取得AppList.html中传递的PackageID,并将PackageId拼装到plist中并输出
			String PackageID = param.substring(param.lastIndexOf(":")+1) ;
			String responseText = this.cereatePlist(this.getServletContext()
					.getRealPath("/"), PackageID);

			OutputStream os = response.getOutputStream();
			byte stringMsg[] = responseText.getBytes();
			os.write(stringMsg);
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (JDOMException e) {
			e.printStackTrace();
		}
	}
	
	private String cereatePlist(String path, String PackageID)
			throws IOException, SQLException, JDOMException {
		SAXBuilder sb = new SAXBuilder();
		// 加载plist模板
		Document doc = sb.build(new File(path + "manifest.plist"));
		
		Element root = doc.getRootElement(); // 获取根元素
		Element root2 = root.getChild("dict");
		Element root3 = root2.getChild("array");
		Element root4 = root3.getChild("dict");
		Element root5 = root4.getChild("array");
		
		Element metadataDict = root4.getChild("dict") ;

		List root6 = root5.getChildren("dict");

		Element msg = (Element) root6.get(0);
		List stringList = msg.getChildren("string");
		Element msgIpa = (Element) stringList.get(1);
		
		//System.out.println(PackageID);
		// 指向app下载的路径
		msgIpa.setText("http://192.168.2.101:8080/JustsyApp/Applet?action=downPlist:ContentTypeID=1:PackageID="
				+ PackageID);

		Element msg2 = (Element) root6.get(1);
		List stringList2 = msg2.getChildren("string");
		Element msgImg = (Element) stringList2.get(1);
		// 指向小图片显示地址
		msgImg.setText("http://192.168.2.101:8080/JustsyApp/Applet?action=downImg:ContentTypeID=4:PackageID="+PackageID);
		Element msg3 = (Element) root6.get(2);
		List stringList3 = msg3.getChildren("string");
		Element msgSmallImg = (Element) stringList3.get(1);
		// 指向大图片显示地址
		msgSmallImg.setText("http://192.168.2.101:8080/JustsyApp/Applet?action=downImg:ContentTypeID=5:PackageID="+PackageID);
		
		
		InputStream stream = getAppInfoStream("{"+PackageID+"}") ;
		saxContentInfo(metadataDict,stream) ;
		
		Format format = Format.getPrettyFormat();
		XMLOutputter xmlout = new XMLOutputter(format);
		ByteArrayOutputStream bo = new ByteArrayOutputStream();
		xmlout.output(doc, bo);
		String xmlStr = bo.toString();
		System.out.println("xml created!!!");
		bo.flush() ;
		bo.close() ;
		System.out.println(xmlStr);
		return xmlStr;

	}
	
	// getContentInfo
	// 对软件信息进行解析
	
	private void saxContentInfo(Element metaData,InputStream stream) throws JDOMException, IOException{
		
		List strings = metaData.getChildren("string") ;
		Element identifier = (Element) strings.get(0) ;
		Element version = (Element) strings.get(1) ;
		Element subtitle = (Element) strings.get(3) ;
		Element title = (Element) strings.get(4) ;
		
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance() ;
		
		try {
			DocumentBuilder builder = factory.newDocumentBuilder() ;
			org.w3c.dom.Document doc = builder.parse(stream) ;
			
			String val1 = doc.getElementsByTagName("CFBundleIdentifier").item(0).getFirstChild().getNodeValue() ;
			String val2 = doc.getElementsByTagName("CFBundleVersion").item(0).getFirstChild().getNodeValue() ;
			String val3 = doc.getElementsByTagName("CFBundleName").item(0).getFirstChild().getNodeValue() ;
			String val4 = doc.getElementsByTagName("CFBundleDisplayName").item(0).getFirstChild().getNodeValue() ;
			//System.out.println(val);
			identifier.setText(val1) ;
			version.setText(val2) ;
			subtitle.setText(val3) ;
			title.setText(val4) ;
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		}
	}
	
	
	private InputStream getAppInfoStream(String packageId) throws SQLException, IOException {
		//String str = "" ;
		DBManager db = new DBManager();
		Connection conn = db.createConn();
		
		String sql = "select * from A_PRFL_PACKAGE_CONTENT where PackageID= ? and ContentTypeID=1";
		PreparedStatement pstmt = conn.prepareStatement(sql) ;
		pstmt.setString(1, packageId) ;
		ResultSet rs = pstmt.executeQuery();
		rs.next() ;
		InputStream stream = rs.getBinaryStream("ContentVersion") ;
		
		
		//rs.close() ;
		//pstmt.close() ;
		
		return stream ;
	}

}


上面的代码我也解释一下,取得传递的参数从数据库中取得详细信息组装xml文件。剩下的都是很普通的代码自己可以根据需求改一下就可以用了。


四、好走到这一步,数据库读取数据没问题的话就可以进行应用的下载安装了,但是在实际的测试中遇到下载速度相当的缓慢不知道什么原因。


五、在实际服务器端读取数据库中应用时,出现读取数据库(数据库使用的是sybase数据库)二进制文件32k的限制,后来在网上找到问题的解决方案。具体就是statement中设置set textsize 50000000,



/**
	 * 下载app
	 * 
	 * @param response
	 * @throws IOException
	 * @throws SQLException
	 */
	private void downloadApp(HttpServletResponse response,
			HttpServletRequest request) throws IOException, SQLException {
		DBManager db = new DBManager();
		Connection conn = db.createConn();

		String param = request.getParameter("action");
		// System.out.println(param);
		String packageId = this.getParameter(param, "PackageID");
		packageId = "{" + packageId + "}";

		String sql = "select * from A_PRFL_PACKAGE_CONTENT where PackageID='"
				+ packageId + "' and ContentTypeID=1";
		System.out.println(sql);
		Statement stmt = conn.createStatement();
		stmt.executeUpdate("set textsize 50000000");
		ResultSet rs = stmt.executeQuery(sql);
		if (!rs.next()) {
			return;
		}
		String appName = rs.getString("ContentFileName");
		InputStream inputStream = rs.getBinaryStream("ContentData");
		// conn.close();

		sendDownload(response, inputStream, appName);
	}



六、注意点plist中的ipa和图片地址不要使用https协议,可能导致应用无法下载。


Ok,,现在在ipad上测试点击应用的连接就可以进行应用的下载了

你可能感兴趣的:(IOS,string,数据库,sybase,stream,function,list)