主流程
- 主线流程:先match action, 再match data, 最后match category
- 时序图
简化后的代码
public final int match(String action, String type, String scheme, Uri data, Set<String> categories, String logTag) { if (action != null && !matchAction(action)) { return NO_MATCH_ACTION; } int dataMatch = matchData(type, scheme, data); if (dataMatch < 0) { return dataMatch; } String categoryMismatch = matchCategories(categories); if (categoryMismatch != null) { return NO_MATCH_CATEGORY; } return dataMatch; }
子流程
match action
- 这个子流程很简单,只判断action是否包含在intent filter
代码
/** * Match this filter against an Intent's action. If the filter does not * specify any actions, the match will always fail. * * @param action The desired action to look for. * * @return True if the action is listed in the filter. */ public final boolean matchAction(String action) { return hasAction(action); } public final boolean hasAction(String action) { return action != null && mActions.contains(action); }
match data
- 这个子流程稍显复杂,代码出口太多,结合uri的语法组成来看[scheme:]scheme-specific-part[#fragment] / [scheme:][//authority][path][?query][#fragment]
代码
/** * Match this filter against an Intent's data (type, scheme and path). If * the filter does not specify any types and does not specify any * schemes/paths, the match will only succeed if the intent does not * also specify a type or data. If the filter does not specify any schemes, * it will implicitly match intents with no scheme, or the schemes "content:" * or "file:" (basically performing a MIME-type only match). If the filter * does not specify any MIME types, the Intent also must not specify a MIME * type. * * <p>Be aware that to match against an authority, you must also specify a base * scheme the authority is in. To match against a data path, both a scheme * and authority must be specified. If the filter does not specify any * types or schemes that it matches against, it is considered to be empty * (any authority or data path given is ignored, as if it were empty as * well). * * <p><em>Note: MIME type, Uri scheme, and host name matching in the * Android framework is case-sensitive, unlike the formal RFC definitions. * As a result, you should always write these elements with lower case letters, * and normalize any MIME types or Uris you receive from * outside of Android to ensure these elements are lower case before * supplying them here.</em></p> * * @param type The desired data type to look for, as returned by * Intent.resolveType(). * @param scheme The desired data scheme to look for, as returned by * Intent.getScheme(). * @param data The full data string to match against, as supplied in * Intent.data. * * @return Returns either a valid match constant (a combination of * {@link #MATCH_CATEGORY_MASK} and {@link #MATCH_ADJUSTMENT_MASK}), * or one of the error codes {@link #NO_MATCH_TYPE} if the type didn't match * or {@link #NO_MATCH_DATA} if the scheme/path didn't match. * * @see #match */ public final int matchData(String type, String scheme, Uri data) { final ArrayList<String> types = mDataTypes; final ArrayList<String> schemes = mDataSchemes; int match = MATCH_CATEGORY_EMPTY; //1. 若filter的type scheme为空,且intent的type data也为空则匹配 // 否则不匹配 if (types == null && schemes == null) { return ((type == null && data == null) ? (MATCH_CATEGORY_EMPTY+MATCH_ADJUSTMENT_NORMAL) : NO_MATCH_DATA); } if (schemes != null) { //2. 若filter的schemes不为空且intent的scheme包含在里面则进行后续判断; // 否则不匹配 if (schemes.contains(scheme != null ? scheme : "")) { match = MATCH_CATEGORY_SCHEME; } else { return NO_MATCH_DATA; } final ArrayList<PatternMatcher> schemeSpecificParts = mDataSchemeSpecificParts; if (schemeSpecificParts != null) { //3. 若schemeSpecificParts不为空,则用data的SchemeSpecificPart来做匹配 // 并修改match的值。uri语法:[scheme:]scheme-specific-part[#fragment] / [scheme:][//authority][path][?query][#fragment] match = hasDataSchemeSpecificPart(data.getSchemeSpecificPart()) ? MATCH_CATEGORY_SCHEME_SPECIFIC_PART : NO_MATCH_DATA; } if (match != MATCH_CATEGORY_SCHEME_SPECIFIC_PART) { // If there isn't any matching ssp, we need to match an authority. final ArrayList<AuthorityEntry> authorities = mDataAuthorities; // 4. 若schemeSpecificPart(ssp)不匹配,则要匹配authority // 也就是判断host port部分 if (authorities != null) { int authMatch = matchDataAuthority(data); if (authMatch >= 0) { // 5. host port匹配,则继续进行path的匹配 final ArrayList<PatternMatcher> paths = mDataPaths; if (paths == null) { match = authMatch; } else if (hasDataPath(data.getPath())) { match = MATCH_CATEGORY_PATH; } else { return NO_MATCH_DATA; } } else { // host port不匹配 return NO_MATCH_DATA; } } } // If neither an ssp nor an authority matched, we're done. if (match == NO_MATCH_DATA) { return NO_MATCH_DATA; } } else { // filter的schemeSpecificParts不为空且和intent的SchemeSpecificPart匹配时, // 若scheme不是"" "content" "file" 就不匹配;否则继续后续判断 // Special case: match either an Intent with no data URI, // or with a scheme: URI. This is to give a convenience for // the common case where you want to deal with data in a // content provider, which is done by type, and we don't want // to force everyone to say they handle content: or file: URIs. if (scheme != null && !"".equals(scheme) && !"content".equals(scheme) && !"file".equals(scheme)) { return NO_MATCH_DATA; } } if (types != null) { // 6. type即MIME // 若type不为空则判断filter和intent的type是否包容,否则不匹配 if (findMimeType(type)) { match = MATCH_CATEGORY_TYPE; } else { return NO_MATCH_TYPE; } } else { // If no MIME types are specified, then we will only match against // an Intent that does not have a MIME type. if (type != null) { // 若filter的types集合是空,但intent的不是空,不匹配 return NO_MATCH_TYPE; } } return match + MATCH_ADJUSTMENT_NORMAL; }
match category
- 这个子流程也不复杂,只判断intent的category是否完全包含在filter里
代码
/** * Match this filter against an Intent's categories. Each category in * the Intent must be specified by the filter; if any are not in the * filter, the match fails. * * @param categories The categories included in the intent, as returned by * Intent.getCategories(). * * @return If all categories match (success), null; else the name of the * first category that didn't match. */ public final String matchCategories(Set<String> categories) { if (categories == null) { return null;//匹配成功 } Iterator<String> it = categories.iterator(); if (mCategories == null) {//filter没有Categories;intent有则失败,无则成功 return it.hasNext() ? it.next() : null; } while (it.hasNext()) {//filter有Categories, intent的Categories要全部包含在filter里才算成功 final String category = it.next(); if (!mCategories.contains(category)) { return category; } } return null; }
小结
- 匹配过程总体分三步走,match action-> match data-> match categories,任意一步失败就不在进行后续处理。
- match action就是匹配intent的action是否包含在filter的actions里。
- match data的思路和uri的语法组成有关[scheme:]scheme-specific-part[#fragment]
- 先判filter和intent的types(即MIMI) schemes是否全是null,若是则匹配,取值MATCH_CATEGORY_EMPTY,否则继续
- 再匹配scheme,不匹配则结束,匹配则继续
- SchemeSpecificPart部分,若匹配,则进行最后的type(MIME)判断
- SchemeSpecificPart部分,若不匹配,则
- 匹配host port部分,成功则继续,否则不匹配
- 匹配path部分,成功则继续,否则不匹配
- 最后进行type(MIME)的匹配
- match categories就是判断intent的所有category是否全都包含啊filter的categories里。
- uri的语法组成[scheme:]scheme-specific-part[#fragment] / [scheme:][//authority][path][?query][#fragment]