2012-03-09 4 views
42

나는 a library to allow apps to self-update에서 일하고 있는데, 안드로이드 마켓 외부로 배포되는 사람들을 위해.ContentProvider에서 APK를 설치할 수 있습니까?

내 원래 계획은 내부 스토리지에 APK 파일을 다운로드 한 다음 ContentProvidercontent://Uri을 통해 거기에서 그것을 설치합니다 코드를 포함하는 것이었다. 그러나, 내가 그것을 시도했을 때, 설치 시스템은 LogCat에 "dipping skir :"경고를 덤프하고 실제로 설치하지 못했습니다. APK를 외부 저장소로 다운로드 한 후 ACTION_VIEW 설치 프로그램 Intent과 함께 file://Uri을 사용하면 APK가 작동했습니다.

parsePackage()에 의해 "Skipping dir :"메시지가 PackageParser에 기록 된 것으로 보입니다.이 메시지는 File으로 작동한다고 가정합니다. 이는 content://Uri 값을 사용할 수 없다는 것을 의미합니다.

누구 성공적으로 content://Uriapplication/vnd.android.package-archiveIntentACTION_VIEW을 사용 했습니까? 그렇다면 ContentProvider을 설정 한 특정 트릭이 있습니까?

감사합니다.

+0

이 ContentProvider가 얼마나 특별하게 보이는지 (특히 openFile 구현)? – Selvin

+1

@Selvin :'openFile()'구현을 가진'ContentProvider'는 파일을 제공하기 위해 필요한 것이고, [내가 일반적으로 잘 알고있는 기존의 간단한 구현] (https://github.com/)을 사용했습니다. commonsguy/cw-advandroid/tree/master/ContentProvider/Files)를 기반으로합니다. 내 질문은 누군가가 성공적으로이 작업을 얻었는지 여부입니다. 소스 코드를 읽는 것은'ContentProvider'가 어떻게 보이는지에 관계없이 지원되지 않는다고 제안합니다. – CommonsWare

+0

아직 시도하지는 않았지만 여기에 설명 된 방법을 보았습니다. http://stackoverflow.com/a/4605040/377260 –

답변

12

자바 API가 허용하지 않는 것처럼 나는 이것이 가능하지 않다고 가정합니다. ContentProvider의 openFile()ParcelFileDescriptor을 반환하며 그 중 java.io.FileDescriptor을 얻을 수 있습니다. 그런 다음 FileDescriptor을 사용하여 FileInputStream 또는 FileOutputStream 중 하나를여십시오. 안타깝게도 RandomAccessFile을 열 수는 없지만 (다른 사람들과 똑같은 설명자에서 RandomAccessFile이 작동한다고해도 필요한 생성자는 API에서 누락 된 것입니다).

APK 파일이 순서대로 읽히지 않아야하므로 (파일 디렉토리를 찾으려면 끝까지 찾아야합니다.) 설치 구현에 RandomAccessFile이 필요하다고 가정합니다. 구현하려는 사례를 지원할 수 있습니다.

+1

나는 당신의 평가에 동의하지만 당신의 분석이 나의 것보다 다른 길을 걷는 동안 그것은 여전히 ​​내가 어디에 있는지 - "잘 모르겠다 * 가능하다"라고 생각합니다. 나는 좀 더 결정적인 것을 기다리고있다. :-) 나는 당신의 대답을 받아 들일 것입니다, 만약 내가 더 좋은 것을 얻지 못하면. 감사! – CommonsWare

+0

설치를 처리하는 PackageManagerService는 APK 파일의 복사본을 생성하므로 원본 URI에서 검색 기능을 스트림에 제공 할 필요가 없습니다. –

+0

나는 컨텐츠 제공자 (나는 나의 프로젝트 중 하나에 대한 addons를 다운로드하고 컨텐츠 제공자가 제공 한 zip으로 구성)를 통해 zip 내부를 읽었다. – HaMMeReD

6

나는 쥘 분석에 동의, 그리고 콘크리트 정밀도 추가합니다 : APK를에 ACTION_VIEW에 의해 불려 PackageInstallerActivity에서

, 이것은 onCreate() 방법이있다 :

315 String apkPath = mPackageURI.getPath(); 
316 File apkFile = new File(apkPath); 

그리고 이전을 즉, PackageUtil에서이 메소드가 호출된다

73 public static PackageParser.Package getPackageInfo(Uri packageURI) { 
74  final String archiveFilePath = packageURI.getPath(); 
75  PackageParser packageParser = new PackageParser(archiveFilePath); 
76  File sourceFile = new File(archiveFilePath); 
77  DisplayMetrics metrics = new DisplayMetrics(); 
78  metrics.setToDefaults(); 
79  return packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0); 
80 } 

모든이가 패키지 매니저가 할 것을 확인하는 경향은 기대 우리스 파일.

로그는 packageParser.parsePackage에 있으며, Uri에 지정된 경로가 파일인지 여부를 테스트합니다.

import java.io.*; 
import android.content.*; 
import android.database.*; 
import android.net.*; 
import android.os.*; 
import android.preference.PreferenceManager; 
import android.util.Log; 

public class LocalFileContentProvider extends ContentProvider { 
    private static final String URI_PREFIX = "content://your.content.provider.as.per.manifest"; 

    public static String constructUri(String url) { 
     Uri uri = Uri.parse(url); 
     return uri.isAbsolute() ? url : URI_PREFIX + url; 
    } 

    @Override 
    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 

     SharedPreferences app_preferences = PreferenceManager.getDefaultSharedPreferences(getContext()); 

     boolean allowLocal = app_preferences.getBoolean("allowLocalFiles", false); 

     if (allowLocal) {  
      try { 
       File file = new File(uri.getPath()); 

       if (file.isDirectory()) 
        return null; 

       ParcelFileDescriptor parcel = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); 
       return parcel; 
      } catch (Exception e) { 
       return null; 
      } 
     } else { 
      return null; 
     } 

    } 

    @Override 
    public boolean onCreate() { 
     return true; 
    } 

    @Override 
    public int delete(Uri uri, String s, String[] as) { 
     throw new UnsupportedOperationException("Not supported by this provider"); 
    } 

    @Override 
    public String getType(Uri uri) { 
     throw new UnsupportedOperationException("Not supported by this provider"); 
    } 

    @Override 
    public Uri insert(Uri uri, ContentValues contentvalues) { 
     throw new UnsupportedOperationException("Not supported by this provider"); 
    } 

    @Override 
    public Cursor query(Uri uri, String[] as, String s, String[] as1, String s1) { 
     throw new UnsupportedOperationException("Not supported by this provider"); 
    } 

    @Override 
    public int update(Uri uri, ContentValues contentvalues, String s, String[] as) { 
     throw new UnsupportedOperationException("Not supported by this provider"); 
    } 

} 

내 매니페스트

<provider android:name="it.automated.android.kiosk.se.LocalFileContentProvider" 
     android:authorities="it.automated" /> 

를 포함) (당신이 나를에서 이동을하기 전에 사용자 환경 설정 선택 가능)

1

나는 로컬 저장소 나에게 액세스 할 수 있습니다 내 응용 프로그램 중 하나이 있습니다 설치 (또는 작업)를 시작합니다.

Intent viewIntent = new Intent(Intent.ACTION_VIEW); 
viewIntent.setDataAndType(Uri.parse(url), mimeType); 
+0

나는 그것을 다시 시도 할 것이다. 귀하의 코드는 내가 시작한 것과 거의 동일합니다. 이는 질문 자체에 설명 된 결과로 실패했습니다. 감사! – CommonsWare

+0

문제는 공급자 측에 없으므로 API 데모 코드 (http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/content/FileProvider)를 사용한 경우에도 마찬가지입니다. html) 문제는 여전히 지속됩니다. –

+0

완벽하게 작동하는 중개자로 WebView를 사용할 수 있습니다. – Fuzzy

25

ACTION_INSTALL_PACKAGE에 대한 설명서 부정확하다. 그것도 파일을 받아 들일뿐입니다.

내 유일한 제안은 응용 프로그램 파일 영역에서 파일의 복사본을 만들고, 세계에서 읽을 수있게 만들고, 나중에 남은 파일을 정리하는 것입니다.

이전 오답 : // URI (JavaDoc)하지만, 그 전에, 당신이 ACTION_VIEW로 설치 제한하고 있습니다 : 위의 4.0에서 콘텐츠를 받아 들일 ACTION_INSTALL_PACKAGE가 전달 된 URI가 file : // URI라고 가정합니다.

+0

Ooooo ... 예, 그건 새로운 것입니다. 많은 감사합니다! – CommonsWare

+0

시도해 보셨습니까? 'content : //'scheme - "Skipping dir"LogCat 메시지를 사용할 때'ACTION_VIEW'와 같은 결과를 얻습니다. 그리고 설치 프로그램은 멈 춥니 다. – CommonsWare

+1

설명서에 대한 신념이 있었지만 설명서가 잘못 나온 것 같습니다. ACTION_INSTALL_PACKAGE를 서비스하는 코드는 파일 만 받아들입니다. 버그를 등록 할 시간. 죄송합니다. –

관련 문제